home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat 1997 February
/
macformat-047.iso
/
Shareware Plus
/
Developers
/
The Gray Council 1.2.1
/
source
/
PowerPlant
/
GrayCouncilPP.cpp
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Text File
|
1996-11-07
|
111.3 KB
|
4,525 lines
|
[
TEXT/CWIE
]
//
// The Gray Council PowerPlant Adapter
// Copyright ©1996 by Trygve Isaacson. All Rights Reserved.
//
// PowerPlant adapter classes for The Gray Council.
//
// Before using any of the Gray Council source code, read and
// follow the licensing info in the accompanying documentation
// or contact:
// <trygve@bombaydigital.com>
// <http://www.bombaydigital.com>
//
// Also check the web site above to make sure you have the latest version!
//
// The Gray Council provides a set of standard C++ classes that implement
// the standard Apple Grayscale Appearance. The core classes do not
// require any other code such as a particular class framework.
//
// This file defines a set of helper classes that derive from standard
// PowerPlant classes, and interface with the core Gray Council code.
// There are also a couple of attachment subclasses for attaching to
// other pane classes to get a white background and 3D frame.
//
// Normally, to use a Gray Council PowerPlant class, you can simply change the
// class ID of the pane in your Constructor window resource to the
// class ID of the appropriate Gray Council PowerPlant adapter class. For
// example, to use the GC pushbutton, create a normal LButton pane,
// and set its class ID to 'GCpb'. Voila. This also works for the LAttachment
// subclasses defined here.
//
// A couple of the classes use the mUserCon field of the subview to specify
// additional information such as icon IDs, string resource IDs, etc.
//
// If the mUserCon usage conflicts with what you are already doing with it,
// you can use the "extended" pane subclasses (those whose class name ends
// in "PPX" instead of "PP"). These classes read their additional info from
// the pane resource stream instead of using mUserCon. In some cases they
// let you specify additional options in the pane resource that you would
// otherwise have to specify programmatically. The supplied resource file
// named GCCustomPanes.rsrc contains the 'CPPb' custom pane types.
// If you put this file in the Constructor app's folder, or keep it open
// whenever your pane resource file is open, or paste the custom pane
// types into your pane resource file, you can use the extended pane classes
// in Constructor.
//
// Each class here that interfaces to a core AGAObject has a public
// member variable called mAGAObject that points to the actual AGAObject
// subclass object. Certain extended object settings (such as mixed-state
// buttons, proportional and live scrolling, etc.) require you to call
// the AGAObject to set it. The member variable is made public to keep
// these PowerPlant classes as lightweight as possible; you make the call,
// rather than using myriad new functions of the PowerPlant AGA subclasses.
//
// Classes defined below:
// AGAWindowPP -- LWindow subclass that draws a gray background, with the
// background type depending on the LWindow windAttr_Modal flag.
// AGAWindowPPX -- AGAWindowPP (LWindow) subclass, that uses extended
// CPPb data to determine the background type.
// AGADialogBoxPP -- LDialogBox subclass that draws a gray background, with
// the background type depending on the WDEF procID and the LWindow
// windAttr_Modal flag, and replaces the PowerPlant default button outline
// by altering the style of the default button AGAPushButton object.
// AGAWindowPPX -- AGADialogBoxPP (LDialogBox) subclass, that uses extended
// CPPb data to determine the background type.
// AGAPushButtonPP -- LStdButton subclass for AGAPushButton.
// AGACheckBoxPP -- LStdCheckBox subclass for AGACheckBox.
// AGARadioButtonPP -- LStdRadioButton subclass for AGARadioButton.
// AGAIconPushButtonPP -- AGAPushButtonPP (LStdButton) subclass for
// AGAIconPushButton.
// AGAIconPushButtonPPX -- AGAIconPushButtonPP (LStdButton) subclass for
// AGAIconPushButton, that uses extended CPPb data for the icon ID.
// AGAIconCheckBoxPP -- AGACheckBoxPP (LStdCheckBox) subclass for
// AGAIconCheckBox.
// AGAIconCheckBoxPPX -- AGAIconCheckBoxPP (LStdCheckBox) subclass for
// AGAIconCheckBox, that uses extended CPPb data for the icon IDs.
// AGAIconRadioButtonPP -- AGARadioButtonPP (LStdRadioButton) subclass
// for AGAIconRadioButton.
// AGAIconRadioButtonPPX -- AGAIconRadioButtonPP (LStdRadioButton) subclass
// for AGAIconRadioButton, that uses extended CPPb data for the icon IDs.
// AGAGroupBoxPP -- LGroupBox subclass for AGAGroupBox, with primary group
// box appearance.
// AGAGroupBoxPPX -- AGAGroupBoxPP (LGroupBox) subclass for AGAGroupBox,
// that uses extended CPPb data for the box type and gap pane ID.
// AGASecondaryGroupBoxPP -- AGAGroupBoxPP (LGroupBox) subclass for
// AGAGroupBox, with secondary group box appearance.
// AGAScrollBarPP -- LStdControl subclass for AGAScrollBar.
// AGAScrollerPP -- LScroller subclass that replaces the normal LStdControl
// scroll bars with ones of class AGAScrollBarPP, and correctly
// maintain them during scrolling.
// AGAActiveScrollerPP -- LActiveScroller replacement; actually an AGAScrollerPP
// subclass that sets the AGA scroll bars for live scrolling.
// AGASliderPP -- LControl subclass for AGASlider.
// AGASliderPPX -- AGASliderPP (LControl) subclass for AGASlider, that
// uses extended CPPb data for the label strings ID, style, and
// slider justification.
// AGALittleArrowsPP -- LControl subclass for AGALittleArrows.
// AGALittleArrowsPPX -- AGALittleArrowsPP (LControl) subclass for
// AGALittleArrows, that uses extended CPPb data for the linked
// numeric LEditField pane ID.
// AGAPopupMenuPP -- LStdPopupMenu subclass for AGAPopupMenu.
// AGADisclosureTrianglePP -- LControl subclass for AGADisclosureTriangle.
// AGAProgressIndicatorPP -- LControl subclass for AGAProgressIndicator.
// AGAWhiteBackgroundAttachmentPP -- LAttachment subclass that draws a
// white background for the pane to which it is attached.
// AGANotchedWhiteBackgroundAttachmentPP -- AGAWhiteBackgroundAttachmentPP (LAttachment)
// subclass that avoids painting the "notch" at the bottom right.
// AGABorderFrameAttachmentPP -- LAttachment subclass that draws a
// "3D" sunken frame around the pane to which it is attached.
// AGANotchedBorderFrameAttachmentPP -- AGABorderFrameAttachmentPP (LAttachment)
// subclass that accounts for the "notch" at the bottom right.
// AGAEditFieldPP -- LEditField subclass that automatically attaches an
// AGAWhiteBackgroundAttachmentPP and an AGABorderFrameAttachmentPP,
// and also knows how to draw the frame in disabled gray when disabled.
// AGATextEditPP -- LTextEdit subclass that automatically attaches an
// AGAWhiteBackgroundAttachmentPP and an AGABorderFrameAttachmentPP.
// AGASeparatorPP -- LPane subclass for AGASeparator.
// AGACaptionPP -- LCaption subclass for AGAStaticText.
// AGAListBoxPP -- LListBox subclass that automatically attaches an
// AGAWhiteBackgroundAttachmentPP and an AGABorderFrameAttachmentPP,
// and also replaces the normal LFocusBox with an AGAFocusBoxPP so
// that the focus frame appears correct.
// AGANotchedListBoxPP -- AGAListBoxPP (LListBox) subclass that uses an
// AGANotchedWhiteBackgroundAttachmentPP instead of an AGAWhiteBackgroundAttachmentPP.
// AGANotchedFocusListBoxPP -- AGANotchedListBoxPP (LListBox) subclass that
// uses both an AGANotchedWhiteBackgroundAttachmentPP instead of an
// AGAWhiteBackgroundAttachmentPP, and an AGANotchedFocusBoxPP instead of
// an AGAFocusBoxPP.
// AGAFocusBoxPP -- LFocusBox subclass used by AGAListBox to draw the
// list box focus frame.
// AGANotchedFocusBoxPP -- AGAFocusBoxPP (LFocusBox) subclass that draws the
// focus box fitted to the "notch" in the bottom right corner.
// AGAPanelEnclosurePP -- LView+LCommander subclass, used by AGATabPanelPP to
// handle target activation/deactivation between targets inside panels.
// AGATabPanelPP -- LView subclass for AGATabPanel, set for standard large
// tab format using the system font.
// AGATabPanelPPX -- AGATabPanelPP (LView) subclass for AGATabPanel, that
// uses extended CPPb data for the label strings ID, and text traits ID.
// The font size of the text traits resource determines whether the tabs
// are small or large format.
// AGASmallTabPanelPP -- AGATabPanelPP (LView) subclass for AGATabPanel, set
// for standard small tab format using Geneva 10 bold.
//
#include "GrayCouncilPP.h"
#include <UDrawingUtils.h>
#include <UReanimator.h>
// There are 6 places in this file that use run-time type
// information (RTTI). This requires turning on the RTTI switch
// in the CodeWarrior C/C++ Language preferences panel. If for
// some reason you can't do this, simply #define NO_RTTI here
// and the RTTI-dependent code will be skipped. But if you do
// this, check the comments below where the RTTI usage is so
// that you don't violate the constraints that the RTTI usage
// was checking for.
#ifndef NO_RTTI
#include <typeinfo.h>
#endif // NO_RTTI
#pragma segment GrayCouncilPP1
// The URegistrar::RegisterClass calls are making my eyes hurt.
// Define a macro to do it instead. We take advantage of the fact that
// we use the names class_ID and CreateStream in all of our classes.
#define GCPP_REGISTER_CLASS(classname) URegistrar::RegisterClass(classname::class_ID, (ClassCreatorFunc) classname::CreateStream)
OSErr InitGrayCouncilPP()
{
//
// Register our dynamically instantiated pane & attachment subclasses.
//
GCPP_REGISTER_CLASS(AGAWhiteBackgroundAttachmentPP);
GCPP_REGISTER_CLASS(AGANotchedWhiteBackgroundAttachmentPP);
GCPP_REGISTER_CLASS(AGABorderFrameAttachmentPP);
GCPP_REGISTER_CLASS(AGANotchedBorderFrameAttachmentPP);
GCPP_REGISTER_CLASS(AGAWindowPP);
GCPP_REGISTER_CLASS(AGADialogBoxPP);
GCPP_REGISTER_CLASS(AGAPushButtonPP);
GCPP_REGISTER_CLASS(AGACheckBoxPP);
GCPP_REGISTER_CLASS(AGARadioButtonPP);
GCPP_REGISTER_CLASS(AGAIconPushButtonPP);
GCPP_REGISTER_CLASS(AGAIconPushButtonPPX);
GCPP_REGISTER_CLASS(AGAIconCheckBoxPP);
GCPP_REGISTER_CLASS(AGAIconCheckBoxPPX);
GCPP_REGISTER_CLASS(AGAIconRadioButtonPP);
GCPP_REGISTER_CLASS(AGAIconRadioButtonPPX);
GCPP_REGISTER_CLASS(AGAScrollBarPP);
GCPP_REGISTER_CLASS(AGAScrollerPP);
GCPP_REGISTER_CLASS(AGAActiveScrollerPP);
GCPP_REGISTER_CLASS(AGAGroupBoxPP);
GCPP_REGISTER_CLASS(AGAGroupBoxPPX);
GCPP_REGISTER_CLASS(AGASecondaryGroupBoxPP);
GCPP_REGISTER_CLASS(AGASliderPP);
GCPP_REGISTER_CLASS(AGASliderPPX);
GCPP_REGISTER_CLASS(AGALittleArrowsPP);
GCPP_REGISTER_CLASS(AGALittleArrowsPPX);
GCPP_REGISTER_CLASS(AGAPopupMenuPP);
GCPP_REGISTER_CLASS(AGADisclosureTrianglePP);
GCPP_REGISTER_CLASS(AGAProgressIndicatorPP);
GCPP_REGISTER_CLASS(AGAEditFieldPP);
GCPP_REGISTER_CLASS(AGATextEditPP);
GCPP_REGISTER_CLASS(AGASeparatorPP);
GCPP_REGISTER_CLASS(AGAListBoxPP);
GCPP_REGISTER_CLASS(AGANotchedListBoxPP);
GCPP_REGISTER_CLASS(AGANotchedFocusListBoxPP);
GCPP_REGISTER_CLASS(AGAFocusBoxPP);
GCPP_REGISTER_CLASS(AGANotchedFocusBoxPP);
GCPP_REGISTER_CLASS(AGACaptionPP);
GCPP_REGISTER_CLASS(AGAPanelEnclosurePP);
GCPP_REGISTER_CLASS(AGATabPanelPP);
GCPP_REGISTER_CLASS(AGATabPanelPPX);
GCPP_REGISTER_CLASS(AGASmallTabPanelPP);
// Do Core Gray Council initialization.
return InitGrayCouncil();
}
static SInt32 MinSInt32(SInt32 a, SInt32 b) { return (a < b) ? a : b; }
static SInt32 MaxSInt32(SInt32 a, SInt32 b) { return (a > b) ? a : b; }
static SInt32 GetTextTraitsJustification(ResIDT inTextTraitsID)
{
TextTraitsH aTTHandle = UTextTraits::LoadTextTraits(inTextTraitsID);
if (aTTHandle == NULL)
return teFlushDefault;
else
return (**aTTHandle).justification;
}
static void ResetAGAObjectFrame(LPane* itsPane, AGAObject* theAGAObject)
{
// Change the AGA object's bounds to match the pane's new
// bounds. Check for the AGA not yet having been created,
// and tell it not to redraw (it will get a draw message
// with the update event).
if (theAGAObject != NULL)
{
Rect bounds;
(void) itsPane->CalcLocalFrameRect(bounds);
theAGAObject->SetObjectBounds(&bounds, AGAObject::kDontRedraw);
}
}
//
// This is the AGATextStyle constructor that is only available
// when compiling with __PowerPlant__ defined. It is conditionally
// declared in GrayCouncil.h, but implemented here since the symbol
// won't be defined when GrayCouncil.cpp is compiled unless precompiled
// headers are used, which is a bad assumption.
//
AGATextStyle::AGATextStyle(ResIDT inTextTraitsID)
{
// Construct from a PowerPlant Text Traits resource.
TextTraitsH aTTHandle = UTextTraits::LoadTextTraits(inTextTraitsID);
if (aTTHandle == NULL) // likely, cos there is no "0" Txtr resource
{
mFontNum = systemFont; // typically Chicago
mFontSize = 0; // application size, typically 12-point
mFontStyle = normal;
}
else
{
mFontNum = (**aTTHandle).fontNumber;
mFontSize = (**aTTHandle).size;
mFontStyle = (**aTTHandle).style;
if (mFontNum == UTextTraits::fontNumber_Unknown) // means use supplied font name
{
Str255 fontName;
AGA_PLstrcpy(fontName, (**aTTHandle).fontName);
::GetFNum(fontName, &mFontNum);
}
}
}
//
// AGAWindowPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LWindow
AGAWindowPP* AGAWindowPP::CreateStream(LStream* inStream)
{
return new AGAWindowPP(inStream);
}
AGAWindowPP::AGAWindowPP(LStream* inStream)
: Inherited(inStream)
{
if (this->HasAttribute(windAttr_Modal))
mBackgroundKind = kRaisedModalBackground;
else
mBackgroundKind = kRaisedModelessBackground;
}
AGAWindowPP::~AGAWindowPP()
{
}
void AGAWindowPP::FinishCreate()
{
// Make sure that the gray background color is installed
// prior to subpanes having their FinishCreateSelf method
// called.
this->SetForeAndBackColors(NULL, &gAGARamp[r2]);
this->ApplyForeAndBackColors();
Inherited::FinishCreate();
}
void AGAWindowPP::FinishCreateSelf()
{
// Let LWindow do its normal stuff first.
Inherited::FinishCreateSelf();
// Either modify the WCTB background color, or
// just set QD background color.
if (mBackgroundKind == kFlatWindowBackground)
ThrowIfOSErr_(AGAInstallGrayWCTB(mMacWindowP));
else if (mBackgroundKind != kNoBackgroundPaint)
this->SetForeAndBackColors(NULL, &gAGARamp[r2]);
}
void AGAWindowPP::DrawSelf()
{
if (mBackgroundKind == kNoBackgroundPaint)
Inherited::DrawSelf();
else
{
// Change normal DrawSelf by drawing our background.
if (this->HasAttribute(windAttr_EraseOnUpdate))
this->DrawBackground(&mMacWindowP->portRect, true, mActive == triState_On);
this->DrawSizeBox();
}
}
void AGAWindowPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// For raised backgrounds,
// if the window size is changing in either direction, we need
// to invalidate the right/bottom edge pixels that will
// need to turn gray when the window is expanded, either before
// or after the resize.
this->InvalidateEdges(true, inWidthDelta, inHeightDelta);
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
this->InvalidateEdges(false, inWidthDelta, inHeightDelta);
}
void AGAWindowPP::ActivateSelf()
{
// Redraw just the edge pixels that change based on active state.
this->FocusDraw();
this->DrawBackground(&mMacWindowP->portRect, false, true);
Inherited::ActivateSelf();
}
void AGAWindowPP::DeactivateSelf()
{
// Redraw just the edge pixels that change based on active state.
this->FocusDraw();
this->DrawBackground(&mMacWindowP->portRect, false, false);
Inherited::DeactivateSelf();
}
void AGAWindowPP::DrawBackground(const Rect* area, Boolean fill, Boolean active)
{
if (mBackgroundKind != kNoBackgroundPaint)
AGABackgroundPaint(area, fill, mBackgroundKind, active, this->HasAttribute(windAttr_SizeBox));
}
void AGAWindowPP::InvalidateEdges(Boolean before, Int16 inWidthDelta, Int16 inHeightDelta)
{
if ((mBackgroundKind == kRaisedModelessBackground) ||
(mBackgroundKind == kRaisedModalBackground))
{
// Invalidate the extra "edge" pixels that need to be redrawn
// when the window is resized.
Rect bounds;
Rect rectToInvalidate;
this->CalcPortFrameRect(bounds);
if (((inWidthDelta > 0) && before) ||
((inWidthDelta < 0) && ! before))
{
rectToInvalidate = bounds;
rectToInvalidate.left = rectToInvalidate.right - 1;
this->InvalPortRect(&rectToInvalidate);
}
if (((inHeightDelta > 0) && before) ||
((inHeightDelta < 0) && ! before))
{
rectToInvalidate = bounds;
rectToInvalidate.top = rectToInvalidate.bottom - 1;
this->InvalPortRect(&rectToInvalidate);
}
if (this->HasAttribute(windAttr_EraseOnUpdate))
{
rectToInvalidate = bounds;
rectToInvalidate.left = rectToInvalidate.right - 16;
rectToInvalidate.top = rectToInvalidate.bottom - 16;
this->InvalPortRect(&rectToInvalidate);
}
}
}
//
// AGAWindowPPX ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAWindowPP
AGAWindowPPX* AGAWindowPPX::CreateStream(LStream* inStream)
{
return new AGAWindowPPX(inStream);
}
AGAWindowPPX::AGAWindowPPX(LStream* inStream)
: Inherited(inStream)
{
inStream->ReadData(&mBackgroundKind, sizeof(mBackgroundKind));
}
AGAWindowPPX::~AGAWindowPPX()
{
}
//
// AGADialogBoxPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LDialogBox
AGADialogBoxPP* AGADialogBoxPP::CreateStream(LStream* inStream)
{
return new AGADialogBoxPP(inStream);
}
AGADialogBoxPP::AGADialogBoxPP(LStream* inStream)
: Inherited(inStream)
{
mDeleteDefaultOutline = false;
mBackgroundKind = kFlatWindowBackground;
//
// We need to determine the window proc ID in order to really
// decide what kind of background to do. So, let's find out
// the same way that PowerPlant does. The SWindowInfo back
// there in the stream contains a WINDid field, which is the
// id of a 'WIND' resource. The 'WIND' resource has the proc ID.
//
SInt32 originalMarker = inStream->GetMarker();
// Undo the LDialogBox stream read.
inStream->SetMarker(-sizeof(PaneIDT), streamFrom_Marker);
inStream->SetMarker(-sizeof(PaneIDT), streamFrom_Marker);
// Undo the LWindow stream read.
inStream->SetMarker(-sizeof(SWindowInfo), streamFrom_Marker);
// Re-read the SWindowInfo.
SWindowInfo windowInfo;
inStream->ReadData(&windowInfo, sizeof(SWindowInfo));
// Peek into the 'WIND' resource, as done by LWindow::MakeMacWindow.
SWINDResourceH theWIND = (SWINDResourceH) ::GetResource('WIND', windowInfo.WINDid);
SInt16 procID = (**theWIND).procID;
::ReleaseResource((Handle) theWIND);
// Restore the stream marker.
inStream->SetMarker(originalMarker, streamFrom_Start);
// Now determine the background kind based on the procID.
if ((procID == dBoxProc) || (procID == movableDBoxProc))
mBackgroundKind = kFlatWindowBackground;
else if (this->HasAttribute(windAttr_Modal))
mBackgroundKind = kRaisedModalBackground;
else
mBackgroundKind = kRaisedModelessBackground;
}
AGADialogBoxPP::~AGADialogBoxPP()
{
}
void AGADialogBoxPP::FinishCreate()
{
// Make sure that the gray background color is installed
// prior to subpanes having their FinishCreateSelf method
// called.
this->SetForeAndBackColors(NULL, &gAGARamp[r2]);
this->ApplyForeAndBackColors();
Inherited::FinishCreate();
}
void AGADialogBoxPP::FinishCreateSelf()
{
// Let LDialogBox do its normal stuff first.
Inherited::FinishCreateSelf();
// Either modify the WCTB background color, or
// just set QD background color.
if (mBackgroundKind == kFlatWindowBackground)
ThrowIfOSErr_(AGAInstallGrayWCTB(mMacWindowP));
else if (mBackgroundKind != kNoBackgroundPaint)
this->SetForeAndBackColors(NULL, &gAGARamp[r2]);
//
// Now we remove its LDefaultOutline and set the
// default our way.
//
if (mDefaultOutline != NULL)
{
delete mDefaultOutline;
mDefaultOutline = NULL;
}
this->SetDefaultButton(mDefaultButtonID);
}
void AGADialogBoxPP::SetDefaultButton(PaneIDT inButtonID)
{
// If you bypass the RTTI here, you must ensure that the
// panes represented by the mDefaultButtonID and the
// inButtonID are a subclass of AGAPushButtonPP.
AGAPushButtonPP* oldDefaultButton = NULL;
AGAPushButtonPP* newDefaultButton = NULL;
LPane* oldDefaultPane = this->FindPaneByID(mDefaultButtonID);
LPane* newDefaultPane = this->FindPaneByID(inButtonID);
#ifndef NO_RTTI
if (oldDefaultPane != NULL)
oldDefaultButton = dynamic_cast<AGAPushButtonPP*>(oldDefaultPane);
if (newDefaultPane != NULL)
newDefaultButton = dynamic_cast<AGAPushButtonPP*>(newDefaultPane);
#else // NO_RTTI
oldDefaultButton = (AGAPushButtonPP*) oldDefaultPane;
newDefaultButton = (AGAPushButtonPP*) newDefaultPane;
#endif // NO_RTTI
mDefaultButtonID = inButtonID;
if (oldDefaultButton != NULL)
{
if (oldDefaultButton->mAGAObject->IsDefault())
{
// Tell the old default button that it is no longer
// the default. This means insetting its frame.
oldDefaultButton->MoveBy(3, 3, true);
oldDefaultButton->ResizeFrameBy(-6, -6, true);
oldDefaultButton->mAGAObject->SetDefault(AGAObject::kIsNotDefault, AGAObject::kFrameInside);
oldDefaultButton->Refresh();
}
}
else if (mDefaultOutline != nil)
{
// Not an AGA object. Do it the LDialogBox way...
mDefaultOutline->Refresh();
delete mDefaultOutline;
mDefaultOutline = NULL;
}
if (newDefaultButton != NULL)
{
if (! newDefaultButton->mAGAObject->IsDefault())
{
// Tell the new default button that it has become
// the default. This means outsetting its frame.
newDefaultButton->MoveBy(-3, -3, false);
newDefaultButton->ResizeFrameBy(6, 6, false);
newDefaultButton->mAGAObject->SetDefault(AGAObject::kIsDefault, AGAObject::kFrameInside);
newDefaultButton->Refresh();
}
}
else if (newDefaultPane != NULL)
{
// Not an AGA object. Do it the LDialogBox way...
((LControl*) newDefaultPane)->AddListener(this);
mDefaultOutline = new LDefaultOutline(newDefaultPane);
mDefaultOutline->Refresh();
}
}
void AGADialogBoxPP::DrawSelf()
{
if (mBackgroundKind == kNoBackgroundPaint)
Inherited::DrawSelf();
else
{
// Change normal DrawSelf by drawing our background.
if (this->HasAttribute(windAttr_EraseOnUpdate))
this->DrawBackground(&mMacWindowP->portRect, true, mActive == triState_On);
this->DrawSizeBox();
}
}
void AGADialogBoxPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// For raised backgrounds,
// if the window size is changing in either direction, we need
// to invalidate the right/bottom edge pixels that will
// need to turn gray when the window is expanded, either before
// or after the resize.
this->InvalidateEdges(true, inWidthDelta, inHeightDelta);
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
this->InvalidateEdges(false, inWidthDelta, inHeightDelta);
}
void AGADialogBoxPP::ActivateSelf()
{
// Redraw just the edge pixels that change based on active state.
this->FocusDraw();
this->DrawBackground(&mMacWindowP->portRect, false, true);
Inherited::ActivateSelf();
}
void AGADialogBoxPP::DeactivateSelf()
{
// Redraw just the edge pixels that change based on active state.
this->FocusDraw();
this->DrawBackground(&mMacWindowP->portRect, false, false);
Inherited::DeactivateSelf();
}
void AGADialogBoxPP::DrawBackground(const Rect* area, Boolean fill, Boolean active)
{
if (mBackgroundKind != kNoBackgroundPaint)
AGABackgroundPaint(area, fill, mBackgroundKind, active, this->HasAttribute(windAttr_SizeBox));
}
void AGADialogBoxPP::InvalidateEdges(Boolean before, Int16 inWidthDelta, Int16 inHeightDelta)
{
if ((mBackgroundKind == kRaisedModelessBackground) ||
(mBackgroundKind == kRaisedModalBackground))
{
// Invalidate the extra "edge" pixels that need to be redrawn
// when the window is resized.
Rect bounds;
Rect rectToInvalidate;
this->CalcPortFrameRect(bounds);
if (((inWidthDelta > 0) && before) ||
((inWidthDelta < 0) && ! before))
{
rectToInvalidate = bounds;
rectToInvalidate.left = rectToInvalidate.right - 1;
this->InvalPortRect(&rectToInvalidate);
}
if (((inHeightDelta > 0) && before) ||
((inHeightDelta < 0) && ! before))
{
rectToInvalidate = bounds;
rectToInvalidate.top = rectToInvalidate.bottom - 1;
this->InvalPortRect(&rectToInvalidate);
}
if (this->HasAttribute(windAttr_EraseOnUpdate))
{
rectToInvalidate = bounds;
rectToInvalidate.left = rectToInvalidate.right - 16;
rectToInvalidate.top = rectToInvalidate.bottom - 16;
this->InvalPortRect(&rectToInvalidate);
}
}
}
//
// AGADialogBoxPPX ----------------------------------------------------
//
#undef Inherited
#define Inherited AGADialogBoxPP
AGADialogBoxPPX* AGADialogBoxPPX::CreateStream(LStream* inStream)
{
return new AGADialogBoxPPX(inStream);
}
AGADialogBoxPPX::AGADialogBoxPPX(LStream* inStream)
: Inherited(inStream)
{
inStream->ReadData(&mBackgroundKind, sizeof(mBackgroundKind));
}
AGADialogBoxPPX::~AGADialogBoxPPX()
{
}
//
// AGAPushButtonPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LStdButton
AGAPushButtonPP* AGAPushButtonPP::CreateStream(LStream* inStream)
{
return new AGAPushButtonPP(inStream);
}
AGAPushButtonPP::AGAPushButtonPP()
{
mAGAObject = NULL;
}
AGAPushButtonPP::AGAPushButtonPP(LStream* inStream)
: Inherited(inStream)
{
mAGAObject = NULL;
}
AGAPushButtonPP::~AGAPushButtonPP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGAPushButtonPP::SetDescriptor(ConstStringPtr inDescriptor)
{
Inherited::SetDescriptor(inDescriptor);
// Install the new text in the AGA object. Don't tell it
// to redraw; the redraw comes from the caller.
Str255 newText;
this->GetDescriptor(newText);
mAGAObject->SetTitle(newText, AGAObject::kDontRedraw);
}
void AGAPushButtonPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGAPushButtonPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGAPushButtonPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->HideSelf(); // make sure the Control Manager object is not drawn
this->CreateAGAObject();
}
void AGAPushButtonPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGAPushButtonPP::ClickSelf(const SMouseDownEvent &inMouseDown)
{
// Let the AGAObject track the mouse.
if (mAGAObject != NULL)
{
this->FocusDraw();
if (mAGAObject->TrackMouse(inMouseDown.whereLocal))
this->HotSpotResult(this->FindHotSpot(inMouseDown.whereLocal));
}
}
void AGAPushButtonPP::HotSpotAction(SInt16 /*inHotSpot*/, Boolean inCurrInside, Boolean /*inPrevInside*/)
{
// Draw the button based on the new press state.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->DrawButton(inCurrInside);
}
}
void AGAPushButtonPP::EnableSelf()
{
// Let the AGAObject enable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kEnabled, this->IsVisible());
}
}
void AGAPushButtonPP::DisableSelf()
{
// Let the AGAObject disable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kDisabled, this->IsVisible());
}
}
void AGAPushButtonPP::ShowSelf()
{
// Suppress showing the Control Manager control.
}
void AGAPushButtonPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
Str255 title;
(void) this->CalcLocalFrameRect(bounds);
::GetControlTitle(mMacControlH, title);
ThrowIfNil_(mAGAObject = new AGAPushButton(&bounds, AGATextStyle(mTextTraitsID), title));
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
}
//
// AGACheckBoxPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LStdCheckBox
AGACheckBoxPP* AGACheckBoxPP::CreateStream(LStream* inStream)
{
return new AGACheckBoxPP(inStream);
}
AGACheckBoxPP::AGACheckBoxPP()
{
mAGAObject = NULL;
mMaxValue = 2; // otherwise mixed-state SetValue messages will constrain to 1
}
AGACheckBoxPP::AGACheckBoxPP(LStream* inStream)
: Inherited(inStream)
{
mAGAObject = NULL;
mMaxValue = 2; // otherwise mixed-state SetValue messages will constrain to 1
}
AGACheckBoxPP::~AGACheckBoxPP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGACheckBoxPP::SetDescriptor(ConstStringPtr inDescriptor)
{
Inherited::SetDescriptor(inDescriptor);
// Install the new text in the AGA object. Don't tell it
// to redraw; the redraw comes from the caller.
Str255 newText;
this->GetDescriptor(newText);
mAGAObject->SetTitle(newText, AGAObject::kDontRedraw);
}
void AGACheckBoxPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGACheckBoxPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGACheckBoxPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->HideSelf(); // make sure the Control Manager object is not drawn
this->CreateAGAObject();
}
void AGACheckBoxPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGACheckBoxPP::ClickSelf(const SMouseDownEvent &inMouseDown)
{
// Let the AGAObject track the mouse.
if (mAGAObject != NULL)
{
this->FocusDraw();
if (mAGAObject->TrackMouse(inMouseDown.whereLocal))
this->HotSpotResult(this->FindHotSpot(inMouseDown.whereLocal));
}
}
void AGACheckBoxPP::HotSpotAction(SInt16 /*inHotSpot*/, Boolean inCurrInside, Boolean /*inPrevInside*/)
{
// Draw the button based on the new press state.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->DrawButton(inCurrInside);
}
}
void AGACheckBoxPP::EnableSelf()
{
// Let the AGAObject enable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kEnabled, this->IsVisible());
}
}
void AGACheckBoxPP::DisableSelf()
{
// Let the AGAObject disable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kDisabled, this->IsVisible());
}
}
void AGACheckBoxPP::ShowSelf()
{
// Suppress showing the Control Manager control.
}
void AGACheckBoxPP::SetValue(SInt32 inValue)
{
// Set the actual LControl value and the AGA object value.
Inherited::SetValue(inValue);
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetValue(mValue, this->IsVisible());
}
}
void AGACheckBoxPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
Str255 title;
(void) this->CalcLocalFrameRect(bounds);
::GetControlTitle(mMacControlH, title);
ThrowIfNil_(mAGAObject = new AGACheckBox(&bounds, AGATextStyle(mTextTraitsID), title, AGAObject::kNoAutomaticState));
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
mAGAObject->SetValue(this->GetValue(), AGAObject::kDontRedraw);
}
//
// AGARadioButtonPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LStdRadioButton
AGARadioButtonPP* AGARadioButtonPP::CreateStream(LStream* inStream)
{
return new AGARadioButtonPP(inStream);
}
AGARadioButtonPP::AGARadioButtonPP()
{
mAGAObject = NULL;
mMaxValue = 2; // otherwise mixed-state SetValue messages will constrain to 1
}
AGARadioButtonPP::AGARadioButtonPP(LStream* inStream)
: Inherited(inStream)
{
mAGAObject = NULL;
mMaxValue = 2; // otherwise mixed-state SetValue messages will constrain to 1
}
AGARadioButtonPP::~AGARadioButtonPP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGARadioButtonPP::SetDescriptor(ConstStringPtr inDescriptor)
{
Inherited::SetDescriptor(inDescriptor);
// Install the new text in the AGA object. Don't tell it
// to redraw; the redraw comes from the caller.
Str255 newText;
this->GetDescriptor(newText);
mAGAObject->SetTitle(newText, AGAObject::kDontRedraw);
}
void AGARadioButtonPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGARadioButtonPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGARadioButtonPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->HideSelf(); // make sure the Control Manager object is not drawn
this->CreateAGAObject();
}
void AGARadioButtonPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGARadioButtonPP::ClickSelf(const SMouseDownEvent &inMouseDown)
{
// Let the AGAObject track the mouse.
if (mAGAObject != NULL)
{
this->FocusDraw();
if (mAGAObject->TrackMouse(inMouseDown.whereLocal))
this->HotSpotResult(this->FindHotSpot(inMouseDown.whereLocal));
}
}
void AGARadioButtonPP::HotSpotAction(SInt16 /*inHotSpot*/, Boolean inCurrInside, Boolean /*inPrevInside*/)
{
// Draw the button based on the new press state.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->DrawButton(inCurrInside);
}
}
void AGARadioButtonPP::EnableSelf()
{
// Let the AGAObject enable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kEnabled, this->IsVisible());
}
}
void AGARadioButtonPP::DisableSelf()
{
// Let the AGAObject disable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kDisabled, this->IsVisible());
}
}
void AGARadioButtonPP::ShowSelf()
{
// Suppress showing the Control Manager control.
}
void AGARadioButtonPP::SetValue(SInt32 inValue)
{
// Set the actual LControl value and the AGA object value.
Inherited::SetValue(inValue);
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetValue(mValue, this->IsVisible());
}
}
void AGARadioButtonPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
Str255 title;
(void) this->CalcLocalFrameRect(bounds);
::GetControlTitle(mMacControlH, title);
ThrowIfNil_(mAGAObject = new AGARadioButton(&bounds, AGATextStyle(mTextTraitsID), title, kNoGroupID, kNoGroupID, AGAObject::kNoAutomaticState));
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
mAGAObject->SetValue(this->GetValue(), AGAObject::kDontRedraw);
}
//
// AGAIconPushButtonPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAPushButtonPP
AGAIconPushButtonPP* AGAIconPushButtonPP::CreateStream(LStream* inStream)
{
return new AGAIconPushButtonPP(inStream);
}
AGAIconPushButtonPP::AGAIconPushButtonPP()
{
mIconID = MIconButtonObject::kNoIconID;
mFrameType = MIconButtonObject::kAutoFrame;
mImageType = MIconButtonObject::kAutoIconFamily;
}
AGAIconPushButtonPP::AGAIconPushButtonPP(LStream* inStream)
: Inherited(inStream)
{
// Use the mUserCon for the icon ID.
mIconID = mUserCon;
mFrameType = MIconButtonObject::kAutoFrame;
mImageType = MIconButtonObject::kAutoIconFamily;
}
AGAIconPushButtonPP::~AGAIconPushButtonPP()
{
}
void AGAIconPushButtonPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
ThrowIfNil_(mAGAObject = new AGAIconPushButton(&bounds, mIconID, mFrameType, mImageType));
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
}
//
// AGAIconPushButtonPPX ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAIconPushButtonPP
AGAIconPushButtonPPX* AGAIconPushButtonPPX::CreateStream(LStream* inStream)
{
return new AGAIconPushButtonPPX(inStream);
}
AGAIconPushButtonPPX::AGAIconPushButtonPPX(LStream* inStream)
: Inherited(inStream)
{
// Read the icon ID, frame type, and image type from the stream.
inStream->ReadData(&mIconID, sizeof(mIconID));
inStream->ReadData(&mFrameType, sizeof(mFrameType));
inStream->ReadData(&mImageType, sizeof(mImageType));
}
AGAIconPushButtonPPX::~AGAIconPushButtonPPX()
{
}
//
// AGAIconCheckBoxPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGACheckBoxPP
AGAIconCheckBoxPP* AGAIconCheckBoxPP::CreateStream(LStream* inStream)
{
return new AGAIconCheckBoxPP(inStream);
}
AGAIconCheckBoxPP::AGAIconCheckBoxPP()
{
mOffIconID = MIconButtonObject::kNoIconID;
mOnIconID = MIconButtonObject::kNoIconID;
mFrameType = MIconButtonObject::kAutoFrame;
mImageType = MIconButtonObject::kAutoIconFamily;
}
AGAIconCheckBoxPP::AGAIconCheckBoxPP(LStream* inStream)
: Inherited(inStream)
{
// Use the mUserCon for both icon IDs.
mOffIconID = mUserCon;
mOnIconID = mUserCon;
mFrameType = MIconButtonObject::kAutoFrame;
mImageType = MIconButtonObject::kAutoIconFamily;
}
AGAIconCheckBoxPP::~AGAIconCheckBoxPP()
{
}
void AGAIconCheckBoxPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
ThrowIfNil_(mAGAObject = new AGAIconCheckBox(&bounds, AGAObject::kNoAutomaticState, mOffIconID, mOnIconID, mFrameType, mImageType));
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
mAGAObject->SetValue(this->GetValue(), AGAObject::kDontRedraw);
}
//
// AGAIconCheckBoxPPX ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAIconCheckBoxPP
AGAIconCheckBoxPPX* AGAIconCheckBoxPPX::CreateStream(LStream* inStream)
{
return new AGAIconCheckBoxPPX(inStream);
}
AGAIconCheckBoxPPX::AGAIconCheckBoxPPX(LStream* inStream)
: Inherited(inStream)
{
// Read the icon IDs, frame type, and image type from the stream.
inStream->ReadData(&mOffIconID, sizeof(mOffIconID));
inStream->ReadData(&mOnIconID, sizeof(mOnIconID));
inStream->ReadData(&mFrameType, sizeof(mFrameType));
inStream->ReadData(&mImageType, sizeof(mImageType));
}
AGAIconCheckBoxPPX::~AGAIconCheckBoxPPX()
{
}
//
// AGAIconRadioButtonPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGARadioButtonPP
AGAIconRadioButtonPP* AGAIconRadioButtonPP::CreateStream(LStream* inStream)
{
return new AGAIconRadioButtonPP(inStream);
}
AGAIconRadioButtonPP::AGAIconRadioButtonPP()
{
mOffIconID = MIconButtonObject::kNoIconID;
mOnIconID = MIconButtonObject::kNoIconID;
mFrameType = MIconButtonObject::kAutoFrame;
mImageType = MIconButtonObject::kAutoIconFamily;
}
AGAIconRadioButtonPP::AGAIconRadioButtonPP(LStream* inStream)
: Inherited(inStream)
{
// Use the mUserCon for both icon IDs.
mOffIconID = mUserCon;
mOnIconID = mUserCon;
mFrameType = MIconButtonObject::kAutoFrame;
mImageType = MIconButtonObject::kAutoIconFamily;
}
AGAIconRadioButtonPP::~AGAIconRadioButtonPP()
{
}
void AGAIconRadioButtonPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
ThrowIfNil_(mAGAObject = new AGAIconRadioButton(&bounds, kNoGroupID, kNoGroupID, AGAObject::kNoAutomaticState, mOffIconID, mOnIconID, mFrameType, mImageType));
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
mAGAObject->SetValue(this->GetValue(), AGAObject::kDontRedraw);
}
//
// AGAIconRadioButtonPPX ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAIconRadioButtonPP
AGAIconRadioButtonPPX* AGAIconRadioButtonPPX::CreateStream(LStream* inStream)
{
return new AGAIconRadioButtonPPX(inStream);
}
AGAIconRadioButtonPPX::AGAIconRadioButtonPPX(LStream* inStream)
: Inherited(inStream)
{
// Read the icon IDs, frame type, and image type from the stream.
inStream->ReadData(&mOffIconID, sizeof(mOffIconID));
inStream->ReadData(&mOnIconID, sizeof(mOnIconID));
inStream->ReadData(&mFrameType, sizeof(mFrameType));
inStream->ReadData(&mImageType, sizeof(mImageType));
}
AGAIconRadioButtonPPX::~AGAIconRadioButtonPPX()
{
}
//
// AGAGroupBoxPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LGroupBox
AGAGroupBoxPP* AGAGroupBoxPP::CreateStream(LStream* inStream)
{
return new AGAGroupBoxPP(inStream);
}
AGAGroupBoxPP::AGAGroupBoxPP()
{
// Assume primary group type, no gap pane.
mAGAObject = NULL;
mIsPrimaryGroup = true;
mGapPaneID = 0;
}
AGAGroupBoxPP::AGAGroupBoxPP(LStream* inStream)
: Inherited(inStream)
{
// Assume primary group type, and use the mUserCon as the
// gap pane's ID.
mAGAObject = NULL;
mIsPrimaryGroup = true;
mGapPaneID = mUserCon;
}
AGAGroupBoxPP::~AGAGroupBoxPP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGAGroupBoxPP::SetDescriptor(ConstStringPtr inDescriptor)
{
Inherited::SetDescriptor(inDescriptor);
// Install the new text in the AGA object. Don't tell it
// to redraw; the redraw comes from the caller.
Str255 newText;
this->GetDescriptor(newText);
mAGAObject->SetTitle(newText, AGAObject::kDontRedraw);
}
void AGAGroupBoxPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGAGroupBoxPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGAGroupBoxPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->CreateAGAObject();
}
void AGAGroupBoxPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGAGroupBoxPP::EnableSelf()
{
// Let the AGAObject enable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kEnabled, this->IsVisible());
}
}
void AGAGroupBoxPP::DisableSelf()
{
// Let the AGAObject disable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kDisabled, this->IsVisible());
}
}
void AGAGroupBoxPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
ThrowIfNil_(mAGAObject = new AGAGroupBox(&bounds, AGATextStyle(mTxtrID), mIsPrimaryGroup, mText));
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
if ((mGapPaneID != 0) && (this->GetSuperView() != NULL))
{
LPane* gapPane = this->GetSuperView()->FindPaneByID(mGapPaneID);
if (gapPane != NULL)
{
Rect bounds;
(void) gapPane->CalcLocalFrameRect(bounds);
mAGAObject->SetTitleGap(5 + bounds.right - bounds.left);
}
}
}
//
// AGAGroupBoxPPX ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAGroupBoxPP
AGAGroupBoxPPX* AGAGroupBoxPPX::CreateStream(LStream* inStream)
{
return new AGAGroupBoxPPX(inStream);
}
AGAGroupBoxPPX::AGAGroupBoxPPX(LStream* inStream)
: Inherited(inStream)
{
// Read the group type and gap pane ID from the stream.
inStream->ReadData(&mIsPrimaryGroup, sizeof(mIsPrimaryGroup));
inStream->ReadData(&mGapPaneID, sizeof(mGapPaneID));
}
AGAGroupBoxPPX::~AGAGroupBoxPPX()
{
}
//
// AGASecondaryGroupBoxPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAGroupBoxPP
AGASecondaryGroupBoxPP* AGASecondaryGroupBoxPP::CreateStream(LStream* inStream)
{
return new AGASecondaryGroupBoxPP(inStream);
}
AGASecondaryGroupBoxPP::AGASecondaryGroupBoxPP()
{
// Set to secondary group box type. Will be used when AGA object
// is created.
mIsPrimaryGroup = false;
}
AGASecondaryGroupBoxPP::AGASecondaryGroupBoxPP(LStream* inStream)
: Inherited(inStream)
{
// Set to secondary group box type. Will be used when AGA object
// is created.
mIsPrimaryGroup = false;
}
AGASecondaryGroupBoxPP::~AGASecondaryGroupBoxPP()
{
}
//
// AGAScrollBarPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LStdControl
AGAScrollBarPP* AGAScrollBarPP::CreateStream(LStream* inStream)
{
return new AGAScrollBarPP(inStream);
}
AGAScrollBarPP::AGAScrollBarPP()
{
mAGAObject = NULL;
mNotificationRoutine = NULL;
mUserData = 0;
mInitWithLiveScrolling = AGAObject::kNoLiveTracking;
}
AGAScrollBarPP::AGAScrollBarPP(LStream* inStream)
: Inherited(inStream)
{
mAGAObject = NULL;
mNotificationRoutine = NULL;
mUserData = 0;
mInitWithLiveScrolling = AGAObject::kNoLiveTracking;
}
AGAScrollBarPP::AGAScrollBarPP(const SPaneInfo &inPaneInfo,
MessageT inValueMessage,
Int32 inValue,
Int32 inMinValue,
Int32 inMaxValue,
Int16 inControlKind,
ResIDT inTextTraitsID,
Str255 inTitle,
Int32 inMacRefCon,
Boolean liveScrolling)
: Inherited(inPaneInfo, inValueMessage, inValue, inMinValue, inMaxValue, inControlKind, inTextTraitsID, inTitle, inMacRefCon)
{
mAGAObject = NULL;
mNotificationRoutine = NULL;
mUserData = 0;
mInitWithLiveScrolling = liveScrolling;
}
AGAScrollBarPP::~AGAScrollBarPP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGAScrollBarPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGAScrollBarPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGAScrollBarPP::InstallNotificationRoutine(AGANotifyPPPtr notificationRoutine, void* userData)
{
// Save the notification routine fn pointer and user data
// for notification handling.
mNotificationRoutine = notificationRoutine;
mUserData = userData;
}
void AGAScrollBarPP::HandleNotification(SInt32 dataValue)
{
// Update the scrollbar value, call the installed notification
// function, and propagate our event number.
this->SetValue(dataValue);
if (mNotificationRoutine != NULL)
(*mNotificationRoutine)(this, dataValue, mUserData);
this->BroadcastValueMessage();
(void) this->FocusDraw(); // HandleEvent may have caused another view to draw
}
void AGAScrollBarPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->HideSelf(); // make sure the Control Manager object is not drawn
this->CreateAGAObject();
}
void AGAScrollBarPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGAScrollBarPP::ClickSelf(const SMouseDownEvent &inMouseDown)
{
// Let the AGAObject track the mouse.
if (mAGAObject != NULL)
{
this->FocusDraw();
if (mAGAObject->TrackMouse(inMouseDown.whereLocal))
this->HotSpotResult(this->FindHotSpot(inMouseDown.whereLocal));
}
}
void AGAScrollBarPP::EnableSelf()
{
// Let the AGAObject enable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kEnabled, this->IsVisible());
}
}
void AGAScrollBarPP::DisableSelf()
{
// Let the AGAObject disable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kDisabled, this->IsVisible());
}
}
void AGAScrollBarPP::ShowSelf()
{
// Suppress showing the Control Manager control.
}
void AGAScrollBarPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
ThrowIfNil_(mAGAObject = new AGAScrollBar(&bounds, mMinValue, mMaxValue, mValue));
mAGAObject->SetLiveTracking(mInitWithLiveScrolling);
mAGAObject->InstallNotificationRoutine(AGAScrollBarPP::RealAGANotifier, this);
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
}
void AGAScrollBarPP::SetValue(SInt32 inValue)
{
// Set the LStdControl value and the AGA object value.
Inherited::SetValue(inValue);
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetValue(mValue, this->IsVisible());
}
}
void AGAScrollBarPP::SetMinValue(SInt32 inMinValue)
{
// Set the LStdControl min and the AGA object min.
Inherited::SetMinValue(inMinValue);
if (mAGAObject != NULL)
{
SInt32 oldMin;
SInt32 oldMax;
this->FocusDraw();
mAGAObject->GetRange(&oldMin, &oldMax);
mAGAObject->SetRange(inMinValue, oldMax, this->IsVisible());
}
}
void AGAScrollBarPP::SetMaxValue(SInt32 inMaxValue)
{
// Set the LStdControl max and the AGA object max.
Inherited::SetMaxValue(inMaxValue);
if (mAGAObject != NULL)
{
SInt32 oldMin;
SInt32 oldMax;
this->FocusDraw();
mAGAObject->GetRange(&oldMin, &oldMax);
mAGAObject->SetRange(oldMin, inMaxValue, this->IsVisible());
}
}
void AGAScrollBarPP::RealAGANotifier(AGATrackingIndicator* /*theIndicator*/, SInt32 dataValue, void* userData)
{
// This is a static function. Cast the user data to get
// the AGAScrollBarPP object, have it handle the notification.
((AGAScrollBarPP*) userData)->HandleNotification(dataValue);
}
//
// AGAScrollerPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LScroller
AGAScrollerPP* AGAScrollerPP::CreateStream(LStream* inStream)
{
return new AGAScrollerPP(inStream);
}
AGAScrollerPP::AGAScrollerPP()
{
mOldHorizontalBar = NULL;
mOldVerticalBar = NULL;
}
AGAScrollerPP::AGAScrollerPP(LStream* inStream)
: Inherited(inStream)
{
mOldHorizontalBar = NULL;
mOldVerticalBar = NULL;
//
// Back up in the stream so we can find out what the
// scroll bar indents are.
//
inStream->SetMarker(-sizeof(SScrollerInfo), streamFrom_Marker);
SScrollerInfo scrollerInfo;
inStream->ReadData(&scrollerInfo, sizeof(SScrollerInfo));
//
// Replace the standard scroll bars with AGA scroll bars.
//
this->MakeCustomScrollBars(scrollerInfo.horizBarLeftIndent,
scrollerInfo.horizBarRightIndent,
scrollerInfo.vertBarTopIndent,
scrollerInfo.vertBarBottomIndent,
AGAObject::kNoLiveTracking);
}
AGAScrollerPP::AGAScrollerPP(LStream* inStream, Boolean liveTracking)
: Inherited(inStream)
{
mOldHorizontalBar = NULL;
mOldVerticalBar = NULL;
//
// Back up in the stream so we can find out what the
// scroll bar indents are.
//
inStream->SetMarker(-sizeof(SScrollerInfo), streamFrom_Marker);
SScrollerInfo scrollerInfo;
inStream->ReadData(&scrollerInfo, sizeof(SScrollerInfo));
//
// Replace the standard scroll bars with AGA scroll bars.
//
this->MakeCustomScrollBars(scrollerInfo.horizBarLeftIndent,
scrollerInfo.horizBarRightIndent,
scrollerInfo.vertBarTopIndent,
scrollerInfo.vertBarBottomIndent,
liveTracking);
}
AGAScrollerPP::~AGAScrollerPP()
{
}
void AGAScrollerPP::FinishCreateSelf()
{
Inherited::FinishCreateSelf();
//
// We can now safely delete the standard scroll bar objects
// that we have replaced with AGA scroll bars.
//
if (mOldHorizontalBar != NULL)
{
mOldHorizontalBar->Hide();
delete mOldHorizontalBar;
mOldHorizontalBar = NULL;
}
if (mOldVerticalBar != NULL)
{
mOldVerticalBar->Hide();
delete mOldVerticalBar;
mOldVerticalBar = NULL;
}
}
void AGAScrollerPP::MakeCustomScrollBars(
Int16 inHorizBarLeftIndent,
Int16 inHorizBarRightIndent,
Int16 inVertBarTopIndent,
Int16 inVertBarBottomIndent,
Boolean liveTracking)
{
//
// NOTE: This code is lifted from LScroller::MakeScrollBars,
// modified to create our scroll bars of our AGAScrollBarPP class
// and use our form of notification that supports live scrolling.
//
SPaneInfo barInfo; // Common information for ScrollBars
barInfo.visible = false; // ScrollBars aren't visible until
barInfo.enabled = true; // Scroller is activated
barInfo.userCon = 0;
barInfo.superView = this;
mOldHorizontalBar = mHorizontalBar;
mHorizontalBar = nil;
if (inHorizBarLeftIndent >= 0) {
// Create Horizontal ScrollBar
barInfo.paneID = PaneIDT_HorizontalScrollBar;
barInfo.width = mFrameSize.width - inHorizBarLeftIndent -
inHorizBarRightIndent;
barInfo.height = 16;
barInfo.bindings.left = true;
barInfo.bindings.right = true;
barInfo.bindings.top = false;
barInfo.bindings.bottom = true;
barInfo.left = inHorizBarLeftIndent;
barInfo.top = mFrameSize.height - 16;
mHorizontalBar = this->MakeCustomScrollBar(barInfo, liveTracking);
((AGAScrollBarPP*) mHorizontalBar)->InstallNotificationRoutine(AGAScrollerPP::ScrollBarNotifier, this);
}
mOldVerticalBar = mVerticalBar;
mVerticalBar = nil;
if (inVertBarTopIndent >= 0) {
// Create Vertical ScrollBar
barInfo.paneID = PaneIDT_VerticalScrollBar;
barInfo.width = 16;
barInfo.height = mFrameSize.height - inVertBarTopIndent -
inVertBarBottomIndent;
barInfo.bindings.left = false;
barInfo.bindings.right = true;
barInfo.bindings.top = true;
barInfo.bindings.bottom = true;
barInfo.left = mFrameSize.width - 16;
barInfo.top = inVertBarTopIndent;
mVerticalBar = this->MakeCustomScrollBar(barInfo, liveTracking);
((AGAScrollBarPP*) mVerticalBar)->InstallNotificationRoutine(AGAScrollerPP::ScrollBarNotifier, this);
}
}
AGAScrollBarPP* AGAScrollerPP::MakeCustomScrollBar(const SPaneInfo& barInfo, Boolean liveTracking)
{
return new AGAScrollBarPP(barInfo, msg_Nothing, 0, 0, 0,
scrollBarProc, 0, "\p", (Int32) this,
liveTracking);
}
void AGAScrollerPP::HandleNotification(LPane* theScrollBar, SInt32 dataValue)
{
// Scroll the image to the new location specified.
// This is similar to what LScroller does when it listens
// to a thumb drag message.
SPoint32 newScrollPosition;
mScrollingView->GetScrollPosition(newScrollPosition);
if (theScrollBar == mHorizontalBar)
newScrollPosition.h = dataValue;
else if (theScrollBar == mVerticalBar)
newScrollPosition.v = dataValue;
mScrollingView->ScrollImageTo(newScrollPosition.h, newScrollPosition.v, true);
this->AdjustScrollBars();
(void) this->FocusDraw(); // scrolling view may have grabbed focus
}
void AGAScrollerPP::AdjustScrollBars()
{
// Check the scrolling view's size compared to ours, so that
// the scroll bars have to correct page and step sizes.
AGAScrollBarPP* horizontalBar = (AGAScrollBarPP*) mHorizontalBar;
AGAScrollBarPP* verticalBar = (AGAScrollBarPP*) mVerticalBar;
SPoint32 scrollUnit;
SDimension16 scrollFrameSize;
SDimension32 scrollImageSize;
SPoint32 scrollPosition;
SPoint32 maxTranslation;
SPoint32 pageStepSize;
SPoint32 pageSize;
mScrollingView->GetScrollUnit(scrollUnit);
mScrollingView->GetFrameSize(scrollFrameSize);
mScrollingView->GetImageSize(scrollImageSize);
mScrollingView->GetScrollPosition(scrollPosition);
// The maxTranslation is the max (pinned) scroll value.
maxTranslation.h = scrollImageSize.width - scrollFrameSize.width;
maxTranslation.v = scrollImageSize.height - scrollFrameSize.height;
// The page step size is how far to scroll page scrolling
pageStepSize.h = MaxSInt32(0, scrollFrameSize.width - scrollUnit.h);
pageStepSize.v = MaxSInt32(0, scrollFrameSize.height - scrollUnit.v);
// The page size is the range that is visible at once.
// It's not the same as the page step size.
if (scrollImageSize.width < 1) // avoid divide by zero or weird negatives
pageSize.h = 1;
else
pageSize.h = maxTranslation.h *
(((float) scrollFrameSize.width) / ((float) scrollImageSize.width));
if (scrollImageSize.height < 1) // avoid divide by zero or weird negatives
pageSize.v = 1;
else
pageSize.v = maxTranslation.v *
(((float) scrollFrameSize.height) / ((float) scrollImageSize.height));
// Update the scroll bar objects with the calculated values.
if (horizontalBar != NULL)
{
horizontalBar->FocusDraw();
horizontalBar->SetMaxValue(maxTranslation.h);
horizontalBar->mAGAObject->SetPageSize(pageSize.h, horizontalBar->IsVisible());
horizontalBar->mAGAObject->SetStepSizes(scrollUnit.h, pageStepSize.h);
horizontalBar->SetValue(scrollPosition.h);
}
if (verticalBar != NULL)
{
verticalBar->FocusDraw();
verticalBar->SetMaxValue(maxTranslation.v);
verticalBar->mAGAObject->SetPageSize(pageSize.v, verticalBar->IsVisible());
verticalBar->mAGAObject->SetStepSizes(scrollUnit.v, pageStepSize.v);
verticalBar->SetValue(scrollPosition.v);
}
}
void AGAScrollerPP::ScrollBarNotifier(LPane* theScrollBar, SInt32 dataValue, void* userData)
{
// This is a static function. Cast the user data to get
// the AGAScrollBarPP object, have it handle the notification.
((AGAScrollerPP*) userData)->HandleNotification(theScrollBar, dataValue);
}
//
// AGAActiveScrollerPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAScrollerPP
AGAActiveScrollerPP* AGAActiveScrollerPP::CreateStream(LStream* inStream)
{
return new AGAActiveScrollerPP(inStream);
}
AGAActiveScrollerPP::AGAActiveScrollerPP()
{
}
AGAActiveScrollerPP::AGAActiveScrollerPP(LStream* inStream)
: Inherited(inStream, AGAObject::kLiveTracking)
{
}
AGAActiveScrollerPP::~AGAActiveScrollerPP()
{
}
//
// AGASliderPP ----------------------------------------------------
//
#pragma segment GrayCouncilPP2
#undef Inherited
#define Inherited LControl
AGASliderPP* AGASliderPP::CreateStream(LStream* inStream)
{
return new AGASliderPP(inStream);
}
AGASliderPP::AGASliderPP()
{
mAGAObject = NULL;
mNotificationRoutine = NULL;
mUserData = 0;
mLabelsResourceID = 0; // STR# resource ID of the slider labels (0 for none)
mLabelsTextTraitsID = -1; // -1 means standard labels style
mSliderJustification = teFlushDefault;
}
AGASliderPP::AGASliderPP(LStream* inStream)
: Inherited(inStream)
{
mAGAObject = NULL;
mNotificationRoutine = NULL;
mUserData = 0;
mLabelsResourceID = mUserCon; // STR# resource ID of the slider labels (0 for none)
mLabelsTextTraitsID = -1; // -1 means standard labels style
mSliderJustification = teFlushDefault;
}
AGASliderPP::~AGASliderPP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGASliderPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGASliderPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGASliderPP::InstallNotificationRoutine(AGANotifyPPPtr notificationRoutine, void* userData)
{
// Save the notification routine fn pointer and user data
// for notification handling.
mNotificationRoutine = notificationRoutine;
mUserData = userData;
}
void AGASliderPP::HandleNotification(SInt32 dataValue)
{
// Update the pane value, call the installed notification
// function, and propagate our event number.
this->SetValue(dataValue);
if (mNotificationRoutine != NULL)
(*mNotificationRoutine)(this, dataValue, mUserData);
this->BroadcastValueMessage();
(void) this->FocusDraw(); // HandleEvent may have caused another view to draw
}
void AGASliderPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->CreateAGAObject();
}
void AGASliderPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGASliderPP::ClickSelf(const SMouseDownEvent &inMouseDown)
{
// Let the AGAObject track the mouse.
if (mAGAObject != NULL)
{
this->FocusDraw();
if (mAGAObject->TrackMouse(inMouseDown.whereLocal))
this->HotSpotResult(this->FindHotSpot(inMouseDown.whereLocal));
}
}
void AGASliderPP::HotSpotResult(SInt16 /*inHotSpot*/)
{
this->SetValue(mAGAObject->GetValue());
}
void AGASliderPP::EnableSelf()
{
// Let the AGAObject enable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kEnabled, this->IsVisible());
}
}
void AGASliderPP::DisableSelf()
{
// Let the AGAObject disable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kDisabled, this->IsVisible());
}
}
void AGASliderPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
if (mLabelsTextTraitsID == -1)
ThrowIfNil_(mAGAObject = new AGASlider(&bounds, mMinValue, mMaxValue, mValue, gAGAStdSmallStyle, mLabelsResourceID));
else
ThrowIfNil_(mAGAObject = new AGASlider(&bounds, mMinValue, mMaxValue, mValue, AGATextStyle(mLabelsTextTraitsID), mLabelsResourceID));
mAGAObject->InstallNotificationRoutine(AGASliderPP::RealAGANotifier, this);
if (mSliderJustification != teFlushDefault)
mAGAObject->SetJustification(mSliderJustification);
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
// The auto-labeling may have increased the range. We need to
// make sure the LControl min/max respect that, or SetValue
// won't work.
SInt32 newMin;
SInt32 newMax;
mAGAObject->GetRange(&newMin, &newMax);
this->SetMinValue(newMin);
this->SetMaxValue(newMax);
// Slider has to erase when drawing, so make sure that
// it doesn't assume we're on a gray background.
this->FocusDraw();
this->ApplyForeAndBackColors();
InstallAGABackgroundColors(mAGAObject, kInstallAlways);
}
void AGASliderPP::SetValue(SInt32 inValue)
{
// Set the slider value.
Inherited::SetValue(inValue);
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetValue(mValue, this->IsVisible());
}
}
void AGASliderPP::SetMinValue(SInt32 inMinValue)
{
// Set the slider min.
Inherited::SetMinValue(inMinValue);
if (mAGAObject != NULL)
{
SInt32 oldMin;
SInt32 oldMax;
this->FocusDraw();
mAGAObject->GetRange(&oldMin, &oldMax);
mAGAObject->SetRange(inMinValue, oldMax, this->IsVisible());
}
}
void AGASliderPP::SetMaxValue(SInt32 inMaxValue)
{
// Set the slider max.
Inherited::SetMaxValue(inMaxValue);
if (mAGAObject != NULL)
{
SInt32 oldMin;
SInt32 oldMax;
this->FocusDraw();
mAGAObject->GetRange(&oldMin, &oldMax);
mAGAObject->SetRange(oldMin, inMaxValue, this->IsVisible());
}
}
void AGASliderPP::RealAGANotifier(AGATrackingIndicator* /*theIndicator*/, SInt32 dataValue, void* userData)
{
// This is a static function. Cast the user data to get
// the AGASliderPP object, have it handle the notification.
((AGASliderPP*) userData)->HandleNotification(dataValue);
}
//
// AGASliderPPX ----------------------------------------------------
//
#undef Inherited
#define Inherited AGASliderPP
AGASliderPPX* AGASliderPPX::CreateStream(LStream* inStream)
{
return new AGASliderPPX(inStream);
}
AGASliderPPX::AGASliderPPX(LStream* inStream)
: Inherited(inStream)
{
// Read the labels STR# ID, labels text traits ID, and
// slider justification from the stream.
inStream->ReadData(&mLabelsResourceID, sizeof(mLabelsResourceID));
inStream->ReadData(&mLabelsTextTraitsID, sizeof(mLabelsTextTraitsID));
inStream->ReadData(&mSliderJustification, sizeof(mSliderJustification));
}
AGASliderPPX::~AGASliderPPX()
{
}
//
// AGALittleArrowsPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LControl
AGALittleArrowsPP* AGALittleArrowsPP::CreateStream(LStream* inStream)
{
return new AGALittleArrowsPP(inStream);
}
AGALittleArrowsPP::AGALittleArrowsPP()
{
mNotificationRoutine = NULL;
mAGAObject = NULL;
mLinkedNumberText = NULL;
mLinkedPaneID = 0;
}
AGALittleArrowsPP::AGALittleArrowsPP(LStream* inStream)
: Inherited(inStream)
{
mNotificationRoutine = NULL;
mAGAObject = NULL;
mLinkedNumberText = NULL;
mLinkedPaneID = mUserCon;
}
AGALittleArrowsPP::~AGALittleArrowsPP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGALittleArrowsPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGALittleArrowsPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGALittleArrowsPP::InstallNotificationRoutine(AGANotifyPPPtr notificationRoutine, void* userData)
{
// Save the notification routine fn pointer and user data
// for notification handling.
mNotificationRoutine = notificationRoutine;
mUserData = userData;
}
void AGALittleArrowsPP::HandleNotification(SInt32 deltaValue)
{
// Update the linked LEditField, if any, call the
// installed notification function, and propagate our
// hot spot result.
SInt32 oldValue;
SInt32 newValue;
if (mLinkedNumberText == NULL)
oldValue = this->GetValue();
else
oldValue = mLinkedNumberText->GetValue();
// Set the LControl value, which will constrain between min and max.
this->SetValue(oldValue + deltaValue);
// Get the new value, which may be been constrained.
newValue = this->GetValue();
// Only set new linked text value if changed.
if ((mLinkedNumberText != NULL) && (newValue != oldValue))
{
mLinkedNumberText->SetValue(newValue);
mLinkedNumberText->Draw(NULL);
mLinkedNumberText->DontRefresh(); // otherwise attachments will flicker after mouse tracking completes
}
if (mNotificationRoutine != NULL)
(*mNotificationRoutine)(this, deltaValue, mUserData);
this->FocusDraw(); // linked edit field prob'ly grabbed focus
}
void AGALittleArrowsPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->CreateAGAObject();
}
void AGALittleArrowsPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGALittleArrowsPP::ClickSelf(const SMouseDownEvent &inMouseDown)
{
// Let the AGAObject track the mouse.
if (mAGAObject != NULL)
{
this->FocusDraw();
// Note that we don't do anything after tracking; the
// notification routine updates the value continuously
// while tracking occurs.
(void) mAGAObject->TrackMouse(inMouseDown.whereLocal);
}
}
void AGALittleArrowsPP::EnableSelf()
{
// Let the AGAObject enable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kEnabled, this->IsVisible());
}
}
void AGALittleArrowsPP::DisableSelf()
{
// Let the AGAObject disable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kDisabled, this->IsVisible());
}
}
void AGALittleArrowsPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
ThrowIfNil_(mAGAObject = new AGALittleArrows(&bounds));
mAGAObject->InstallNotificationRoutine(AGALittleArrowsPP::RealAGANotifier, this);
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
if (mLinkedPaneID != 0)
{
// If you bypass the RTTI here, you must ensure that the
// pane ID specifies a pane that is a subclass of LEditField.
LPane* linkedPane = mSuperView->FindPaneByID(mLinkedPaneID);
if (linkedPane != NULL)
{
#ifndef NO_RTTI
mLinkedNumberText = dynamic_cast<LEditField*>(linkedPane);
#else // NO_RTTI
mLinkedNumberText = (LEditField*) linkedPane;
#endif // NO_RTTI
if (mLinkedNumberText != NULL)
mLinkedNumberText->SetValue(mValue);
}
}
}
void AGALittleArrowsPP::RealAGANotifier(AGALittleArrows* /*theAGAObject*/, SInt32 deltaValue, void* userData)
{
// This is a static function. Cast the user data to get
// the AGAScrollerScrollBarMA object, have it handle the notification.
((AGALittleArrowsPP*) userData)->HandleNotification(deltaValue);
}
//
// AGALittleArrowsPPX ----------------------------------------------------
//
#undef Inherited
#define Inherited AGALittleArrowsPP
AGALittleArrowsPPX* AGALittleArrowsPPX::CreateStream(LStream* inStream)
{
return new AGALittleArrowsPPX(inStream);
}
AGALittleArrowsPPX::AGALittleArrowsPPX(LStream* inStream)
: Inherited(inStream)
{
// Read the linked LEditField pane ID from the stream.
inStream->ReadData(&mLinkedPaneID, sizeof(mLinkedPaneID));
}
AGALittleArrowsPPX::~AGALittleArrowsPPX()
{
}
//
// AGAPopupMenuPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LStdPopupMenu
AGAPopupMenuPP* AGAPopupMenuPP::CreateStream(LStream* inStream)
{
return new AGAPopupMenuPP(inStream);
}
AGAPopupMenuPP::AGAPopupMenuPP(LStream* inStream)
: Inherited(inStream)
{
mAGAObject = NULL;
// When creating the core AGA object, we will need to know
// the title width and title variation of the popup menu.
// Unfortunately, due to the hack nature of the CDEF and the
// design peculiarities of LStdPopupMenu, we have no way to
// access those values. The only solution is to back up in
// the PPob stream and stash them aside until needed.
SInt32 originalMarker = inStream->GetMarker();
// Undo the LStdPopupMenu stream read.
inStream->SetMarker(-sizeof(Int16), streamFrom_Marker);
// Undo the LStdControl stream read.
inStream->SetMarker(-sizeof(Int16), streamFrom_Marker);
inStream->SetMarker(-sizeof(ResIDT), streamFrom_Marker);
inStream->SetMarker(-sizeof(Int32), streamFrom_Marker);
Str255 title;
::GetControlTitle(mMacControlH, title);
inStream->SetMarker(-1 -title[0], streamFrom_Marker);
// Undo the LControl stream read.
inStream->SetMarker(-sizeof(SControlInfo), streamFrom_Marker);
// Finally, re-read the LControl pane data.
SControlInfo controlInfo;
inStream->ReadData(&controlInfo, sizeof(SControlInfo));
mStashedTitleVariation = controlInfo.value; // popup CDEF uses ctl value for other stuff
mStashedTitleWidth = controlInfo.maxValue; // popup CDEF uses ctl max for width
// And skip forward in the stream so it's back where it
// was before we touched it, in case a subclass is reading it.
inStream->SetMarker(originalMarker, streamFrom_Start);
}
AGAPopupMenuPP::~AGAPopupMenuPP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGAPopupMenuPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGAPopupMenuPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGAPopupMenuPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->HideSelf(); // make sure the Control Manager object is not drawn
this->CreateAGAObject();
}
void AGAPopupMenuPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGAPopupMenuPP::ClickSelf(const SMouseDownEvent &inMouseDown)
{
// Let the AGAObject track the mouse.
if (mAGAObject != NULL)
{
this->FocusDraw();
if (mAGAObject->TrackMouse(inMouseDown.whereLocal))
this->SetValue(mAGAObject->GetCurrentItemNo());
}
}
void AGAPopupMenuPP::EnableSelf()
{
// Let the AGAObject enable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kEnabled, this->IsVisible());
}
}
void AGAPopupMenuPP::DisableSelf()
{
// Let the AGAObject disable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kDisabled, this->IsVisible());
}
}
void AGAPopupMenuPP::ShowSelf()
{
// Suppress showing the Control Manager control.
}
void AGAPopupMenuPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
AGAPopupMenu::WidthAdjust widthAdjust;
Rect bounds;
Str255 title;
MenuRef theMenuRef = this->GetMacMenuH();
SInt8 titleJustification = mStashedTitleVariation & 0xFF;
AGATextStyle titleStyle(mTextTraitsID);
if (((mControlKind - popupMenuProc) & popupFixedWidth) != 0)
widthAdjust = AGAPopupMenu::kFixedWidth;
else
widthAdjust = AGAPopupMenu::kSystemMDEFAdjustment;
(void) this->CalcLocalFrameRect(bounds);
::GetControlTitle(mMacControlH, title);
// Look at the wacky popup CDEF title style bits.
titleStyle.mFontStyle = 0; // init to plain text
if ((mStashedTitleVariation & popupTitleBold) != 0)
titleStyle.mFontStyle |= bold;
if ((mStashedTitleVariation & popupTitleItalic) != 0)
titleStyle.mFontStyle |= italic;
if ((mStashedTitleVariation & popupTitleUnderline) != 0)
titleStyle.mFontStyle |= underline;
if ((mStashedTitleVariation & popupTitleOutline) != 0)
titleStyle.mFontStyle |= outline;
if ((mStashedTitleVariation & popupTitleShadow) != 0)
titleStyle.mFontStyle |= shadow;
if ((mStashedTitleVariation & popupTitleCondense) != 0)
titleStyle.mFontStyle |= condense;
if ((mStashedTitleVariation & popupTitleExtend) != 0)
titleStyle.mFontStyle |= extend;
ThrowIfNil_(mAGAObject = new AGAPopupMenu(&bounds, mStashedTitleWidth, title, titleJustification, titleStyle, AGATextStyle(mTextTraitsID), widthAdjust, this->GetMacMenuH(), AGAPopupMenu::kDontDispose));
mAGAObject->SetCurrentItemNo(mValue, AGAObject::kDontRedraw);
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
}
void AGAPopupMenuPP::SetValue(SInt32 inValue)
{
// Set the actual LStdControl value and the AGA object value.
Inherited::SetValue(inValue);
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetCurrentItemNo(mValue, this->IsVisible());
}
}
//
// AGADisclosureTrianglePP ----------------------------------------------------
//
#undef Inherited
#define Inherited LControl
AGADisclosureTrianglePP* AGADisclosureTrianglePP::CreateStream(LStream* inStream)
{
return new AGADisclosureTrianglePP(inStream);
}
AGADisclosureTrianglePP::AGADisclosureTrianglePP()
{
mAGAObject = NULL;
mMaxValue = 1; // make sure SetValue doesn't get stuck at value = 0
}
AGADisclosureTrianglePP::AGADisclosureTrianglePP(LStream* inStream)
: Inherited(inStream)
{
mAGAObject = NULL;
mMaxValue = 1; // make sure SetValue doesn't get stuck at value = 0
}
AGADisclosureTrianglePP::~AGADisclosureTrianglePP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGADisclosureTrianglePP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGADisclosureTrianglePP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGADisclosureTrianglePP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->CreateAGAObject();
}
void AGADisclosureTrianglePP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGADisclosureTrianglePP::ClickSelf(const SMouseDownEvent &inMouseDown)
{
// Let the AGAObject track the mouse.
if (mAGAObject != NULL)
{
this->FocusDraw();
if (mAGAObject->TrackMouse(inMouseDown.whereLocal))
this->HotSpotResult(this->FindHotSpot(inMouseDown.whereLocal));
}
}
void AGADisclosureTrianglePP::HotSpotResult(SInt16 /*inHotSpot*/)
{
this->SetValue(mAGAObject->GetState() ? 1 : 0);
}
void AGADisclosureTrianglePP::EnableSelf()
{
// Let the AGAObject enable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kEnabled, this->IsVisible());
}
}
void AGADisclosureTrianglePP::DisableSelf()
{
// Let the AGAObject disable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kDisabled, this->IsVisible());
}
}
void AGADisclosureTrianglePP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
ThrowIfNil_(mAGAObject = new AGADisclosureTriangle(&bounds, AGAObject::kAutomaticState));
if (mEnabled == triState_Off)
mAGAObject->SetEnable(AGAObject::kDisabled, AGAObject::kDontRedraw);
if (mValue != 0) // allow initial state to be set to kDisclosed
mAGAObject->SetState(AGADisclosureTriangle::kDisclosedState, AGAObject::kDontRedraw);
// Disclosure triangle has to erase when animating, so make sure that
// it doesn't assume we're on a gray background.
this->FocusDraw();
this->ApplyForeAndBackColors();
InstallAGABackgroundColors(mAGAObject, kInstallAlways);
}
void AGADisclosureTrianglePP::SetValue(SInt32 inValue)
{
// Set the actual LControl value and the AGA object state.
Inherited::SetValue(inValue);
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetState(mValue != 0, this->IsVisible());
}
}
//
// AGAProgressIndicatorPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LControl
AGAProgressIndicatorPP* AGAProgressIndicatorPP::CreateStream(LStream* inStream)
{
return new AGAProgressIndicatorPP(inStream);
}
AGAProgressIndicatorPP::AGAProgressIndicatorPP()
{
mAGAObject = NULL;
}
AGAProgressIndicatorPP::AGAProgressIndicatorPP(LStream* inStream)
: Inherited(inStream)
{
mAGAObject = NULL;
}
AGAProgressIndicatorPP::~AGAProgressIndicatorPP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGAProgressIndicatorPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGAProgressIndicatorPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGAProgressIndicatorPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->CreateAGAObject();
}
void AGAProgressIndicatorPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGAProgressIndicatorPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
ThrowIfNil_(mAGAObject = new AGAProgressIndicator(&bounds, mMinValue, mMaxValue));
mAGAObject->SetValue(mValue, AGAObject::kDontRedraw);
if (mUserCon != 0)
this->StartAutoAnimate();
}
void AGAProgressIndicatorPP::SetValue(SInt32 inValue)
{
// Set the value of the LControl and the AGA object.
Inherited::SetValue(inValue);
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetValue(mValue, this->IsVisible());
}
}
void AGAProgressIndicatorPP::SetMinValue(SInt32 inMinValue)
{
// Set the min of the LControl and the AGA object.
Inherited::SetMinValue(inMinValue);
if (mAGAObject != NULL)
{
SInt32 oldMin;
SInt32 oldMax;
this->FocusDraw();
mAGAObject->GetRange(&oldMin, &oldMax);
mAGAObject->SetRange(inMinValue, oldMax, this->IsVisible());
}
}
void AGAProgressIndicatorPP::SetMaxValue(SInt32 inMaxValue)
{
// Set the max of the LControl and the AGA object.
Inherited::SetMaxValue(inMaxValue);
if (mAGAObject != NULL)
{
SInt32 oldMin;
SInt32 oldMax;
this->FocusDraw();
mAGAObject->GetRange(&oldMin, &oldMax);
mAGAObject->SetRange(oldMin, inMaxValue, this->IsVisible());
}
}
void AGAProgressIndicatorPP::SpendTime(const EventRecord& /*inMacEvent*/)
{
// Let the AGAObject do one animation step.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->QuantizedAnimate();
}
}
void AGAProgressIndicatorPP::StartAutoAnimate()
{
// Let LPeriodical remove us from its idle queue.
this->StartIdling();
}
void AGAProgressIndicatorPP::StopAutoAnimate()
{
// Tell LPeriodical to add us to its idle queue.
this->StopIdling();
}
//
// AGAWhiteBackgroundAttachmentPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LAttachment
AGAWhiteBackgroundAttachmentPP* AGAWhiteBackgroundAttachmentPP::CreateStream(LStream* inStream)
{
return new AGAWhiteBackgroundAttachmentPP(inStream);
}
AGAWhiteBackgroundAttachmentPP::AGAWhiteBackgroundAttachmentPP(MessageT inMessage, Boolean inExecuteHost)
: Inherited(inMessage, inExecuteHost)
{
mIsNotched = false;
}
AGAWhiteBackgroundAttachmentPP::AGAWhiteBackgroundAttachmentPP(LStream *inStream)
: Inherited(inStream)
{
mIsNotched = false;
}
Boolean AGAWhiteBackgroundAttachmentPP::Execute(MessageT inMessage, void *ioParam)
{
if (inMessage == msg_DrawOrPrint)
{
AGADrawingEnvironment env;
// Draw the background in white, inset to avoid the border
// frame pixels.
Rect paneFrame = *((Rect*) ioParam);
::RGBForeColor(&gAGARamp[rW]);
::InsetRect(&paneFrame, 1, 1);
if (mIsNotched)
{
Rect r;
r = paneFrame;
r.right -= 15;
::PaintRect(&r);
r = paneFrame;
r.bottom -= 15;
::PaintRect(&r);
}
else
{
::PaintRect(&paneFrame);
}
}
return true; // owner should also do its work
}
//
// AGANotchedWhiteBackgroundAttachmentPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAWhiteBackgroundAttachmentPP
AGANotchedWhiteBackgroundAttachmentPP* AGANotchedWhiteBackgroundAttachmentPP::CreateStream(LStream* inStream)
{
return new AGANotchedWhiteBackgroundAttachmentPP(inStream);
}
AGANotchedWhiteBackgroundAttachmentPP::AGANotchedWhiteBackgroundAttachmentPP(MessageT inMessage, Boolean inExecuteHost)
: Inherited(inMessage, inExecuteHost)
{
mIsNotched = true;
}
AGANotchedWhiteBackgroundAttachmentPP::AGANotchedWhiteBackgroundAttachmentPP(LStream *inStream)
: Inherited(inStream)
{
mIsNotched = true;
}
//
// AGABorderFrameAttachmentPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LAttachment
AGABorderFrameAttachmentPP* AGABorderFrameAttachmentPP::CreateStream(LStream* inStream)
{
return new AGABorderFrameAttachmentPP(inStream);
}
AGABorderFrameAttachmentPP::AGABorderFrameAttachmentPP(MessageT inMessage, Boolean inExecuteHost)
: Inherited(inMessage, inExecuteHost)
{
mIsNotched = false;
}
AGABorderFrameAttachmentPP::AGABorderFrameAttachmentPP(LStream *inStream)
: Inherited(inStream)
{
mIsNotched = false;
}
Boolean AGABorderFrameAttachmentPP::Execute(MessageT inMessage, void *ioParam)
{
if (inMessage == msg_DrawOrPrint)
{
AGADrawingEnvironment env;
// Draw the frame with shading outside.
// If you bypass the RTTI here, the frame will always
// draw enabled. With the 7/96 AGA spec revision, this
// is now visually obvious.
Boolean ownerEnabled = true;
#ifndef NO_RTTI
LPane* ownerPane = dynamic_cast<LPane*>(mOwnerHost);
if (ownerPane != NULL)
ownerEnabled = ownerPane->IsEnabled();
#endif // NO_RTTI
// The sunken border is drawn in the pixel outside the
// pane frame.
Rect paneFrame = *((Rect*) ioParam);
::InsetRect(&paneFrame, -1, -1);
AGADrawBorderFrame(&paneFrame, ownerEnabled, mIsNotched, true /*drawFrame*/, &gAGARamp[r2]);
}
return true; // owner should also do its work
}
//
// AGANotchedBorderFrameAttachmentPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGABorderFrameAttachmentPP
AGANotchedBorderFrameAttachmentPP* AGANotchedBorderFrameAttachmentPP::CreateStream(LStream* inStream)
{
return new AGANotchedBorderFrameAttachmentPP(inStream);
}
AGANotchedBorderFrameAttachmentPP::AGANotchedBorderFrameAttachmentPP(MessageT inMessage, Boolean inExecuteHost)
: Inherited(inMessage, inExecuteHost)
{
mIsNotched = true;
}
AGANotchedBorderFrameAttachmentPP::AGANotchedBorderFrameAttachmentPP(LStream *inStream)
: Inherited(inStream)
{
mIsNotched = true;
}
//
// AGAEditFieldPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LEditField
AGAEditFieldPP* AGAEditFieldPP::CreateStream(LStream* inStream)
{
return new AGAEditFieldPP(inStream);
}
AGAEditFieldPP::AGAEditFieldPP()
{
}
AGAEditFieldPP::AGAEditFieldPP(LStream* inStream)
: Inherited(inStream)
{
}
AGAEditFieldPP::~AGAEditFieldPP()
{
}
void AGAEditFieldPP::DrawSelf()
{
this->DrawEverything();
}
void AGAEditFieldPP::DrawBox()
{
this->DrawEverything();
}
void AGAEditFieldPP::DrawEverything()
{
// LEditField just isn't set up to handle our situations where dimming
// and background color changes affect the whole view. It tries to
// optimize by only drawing the box upon enable/disable messages. But
// our background may change or get painted when that happens. So we catch
// the DrawSelf and separate DrawBox messages, and just draw it all.
Rect r;
RGBColor textForeColor;
RGBColor textBackColor;
Boolean enabled = (mEnabled == triState_On);
(void) this->CalcLocalFrameRect(r);
AGADrawingEnvironment env;
::GetForeColor(&textForeColor);
::GetBackColor(&textBackColor);
::RGBForeColor(&textBackColor);
::InsetRect(&r, 1, 1);
::PaintRect(&r);
::InsetRect(&r, -1, -1);
if (mHasBox)
{
// Note that we just use r2 with AGADrawBorderFrame, because even
// with tab panels, r2 is the correct disabled background color.
::InsetRect(&r, -1, -1);
AGADrawBorderFrame(&r, enabled, false /*isNotched*/, true /*drawFrame*/, &gAGARamp[r2]);
::InsetRect(&r, 3, 3);
}
// Get the text to draw, just as in LEditField::DrawSelf.
// Except we draw gray text if dimmed.
if (enabled)
::RGBForeColor(&textForeColor);
else
::RGBForeColor(&gAGARamp[r7]);
GrafPtr savePort = (**mTextEditH).inPort;
(**mTextEditH).inPort = UQDGlobals::GetCurrentPort();
::TEUpdate(&r, mTextEditH);
(**mTextEditH).inPort = savePort;
// For any non-deep screens, we paint a gray pattern on
// to the text if it's dim.
if (! enabled)
{
GDIterator iter;
Boolean deep;
::PenPat(&qd.gray);
::PenMode(patBic);
while (iter.More(deep))
if (! deep)
::PaintRect(&r);
}
}
//
// AGATextEditPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LTextEdit
AGATextEditPP* AGATextEditPP::CreateStream(LStream* inStream)
{
return new AGATextEditPP(inStream);
}
AGATextEditPP::AGATextEditPP()
{
}
AGATextEditPP::AGATextEditPP(LStream* inStream)
: Inherited(inStream)
{
}
AGATextEditPP::~AGATextEditPP()
{
}
void AGATextEditPP::DrawSelf()
{
// LTextEdit clipping prevents simple attachments from doing the job.
// So we draw the border frame ourself and make sure there's an extra
// pixel of white around the raw TE rect.
Rect r;
RGBColor textForeColor;
RGBColor textBackColor;
Boolean enabled = (mEnabled == triState_On);
(void) this->CalcLocalFrameRect(r);
{ // wrap drawing environment in its own scope
AGADrawingEnvironment env;
RgnHandle savedClipping = ::NewRgn();
::GetClip(savedClipping);
::InsetRect(&r, -3, -3);
::ClipRect(&r);
::GetForeColor(&textForeColor);
::GetBackColor(&textBackColor);
::RGBForeColor(&textBackColor);
AGADrawBorderFrame(&r, enabled, false /*isNotched*/, true /*drawFrame*/, &gAGARamp[r2]);
::InsetRect(&r, 2, 2);
::PaintRect(&r);
::SetClip(savedClipping);
}
Inherited::DrawSelf();
}
//
// AGASeparatorPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LPane
AGASeparatorPP* AGASeparatorPP::CreateStream(LStream* inStream)
{
return new AGASeparatorPP(inStream);
}
AGASeparatorPP::AGASeparatorPP()
{
mAGAObject = NULL;
}
AGASeparatorPP::AGASeparatorPP(LStream* inStream)
: Inherited(inStream)
{
mAGAObject = NULL;
}
AGASeparatorPP::~AGASeparatorPP()
{
// Delete AGA object if we successfully allocated it.
if (mAGAObject != NULL)
delete mAGAObject;
}
void AGASeparatorPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGASeparatorPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGASeparatorPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->CreateAGAObject();
}
void AGASeparatorPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGASeparatorPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
ThrowIfNil_(mAGAObject = new AGASeparator(&bounds));
}
//
// AGACaptionPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LCaption
AGACaptionPP* AGACaptionPP::CreateStream(LStream* inStream)
{
return new AGACaptionPP(inStream);
}
AGACaptionPP::AGACaptionPP()
{
}
AGACaptionPP::AGACaptionPP(LStream* inStream)
: Inherited(inStream)
{
}
AGACaptionPP::~AGACaptionPP()
{
}
void AGACaptionPP::FinishCreateSelf()
{
// Need to erase when drawing, so make sure that
// we doesn't assume we're on a gray background.
(void) DetermineAGABackgroundColors(&mEnabledBackgroundColor, &mDisabledBackgroundColor, kInstallAlways);
}
void AGACaptionPP::DrawSelf()
{
// Erase to gray before letting LCaption do its standard drawing.
Rect bounds;
Boolean enabled = this->IsEnabled();
(void) this->CalcLocalFrameRect(bounds);
AGADrawingEnvironment env;
{
GDIterator iter;
Boolean deep;
while (iter.More(deep))
{
if (deep)
{
if (enabled)
::RGBForeColor(&mEnabledBackgroundColor);
else
::RGBForeColor(&mDisabledBackgroundColor);
}
else
::RGBForeColor(&gAGARamp[rW]);
::PaintRect(&bounds);
}
} // destruct the GDIterator and its clipping changes
// The remaining is lifted from LCaption::DrawSelf(), except that
// we set the text color to dimmed text color if we are not enabled.
Rect frame;
CalcLocalFrameRect(frame);
Int16 just = UTextTraits::SetPortTextTraits(mTxtrID);
RGBColor textColor;
::GetForeColor(&textColor);
ApplyForeAndBackColors();
::TextMode(srcOr);
::RGBForeColor(&textColor);
if (! enabled)
::RGBForeColor(&gAGARamp[r7]);
UTextDrawing::DrawWithJustification((Ptr)&mText[1], mText[0], frame, just);
// For any non-deep screens, we paint a gray pattern on
// to the text if it's dim.
if (! enabled)
{
GDIterator iter;
Boolean deep;
::PenPat(&qd.gray);
::PenMode(patBic);
while (iter.More(deep))
if (! deep)
::PaintRect(&bounds);
}
}
void AGACaptionPP::EnableSelf()
{
// We need to redraw when we are enabled.
this->Draw(NULL);
}
void AGACaptionPP::DisableSelf()
{
// We need to redraw when we are disabled.
this->Draw(NULL);
}
//
// AGAFocusBoxPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LFocusBox
AGAFocusBoxPP* AGAFocusBoxPP::CreateStream(LStream* inStream)
{
return new AGAFocusBoxPP(inStream);
}
AGAFocusBoxPP::AGAFocusBoxPP()
{
mIsNotched = false;
}
AGAFocusBoxPP::AGAFocusBoxPP(const LFocusBox &inOriginal)
: Inherited(inOriginal)
{
mIsNotched = false;
}
AGAFocusBoxPP::AGAFocusBoxPP(LStream* inStream)
: Inherited(inStream)
{
mIsNotched = false;
}
AGAFocusBoxPP::~AGAFocusBoxPP()
{
}
void AGAFocusBoxPP::DrawSelf()
{
// Draw the AGA-style focus frame.
GDIterator iter;
Boolean deep;
Rect bounds;
RgnHandle borderRegion = ::NewRgn();
(void) this->CalcLocalFrameRect(bounds);
AGAComputeTargetBorderRegion(borderRegion, &bounds, mIsNotched);
while (iter.More(deep))
{
if (deep)
::RGBForeColor(&gAGARamp[r8]);
else
::RGBForeColor(&gAGARamp[rB]);
PaintRgn(borderRegion);
}
::DisposeRgn(borderRegion);
}
RgnHandle AGAFocusBoxPP::GetBoxRegion(const Rect &inFrame, const Rect &inRevealed) const
{
RgnHandle boxRgn = ::NewRgn();
AGAComputeTargetBorderRegion(boxRgn, &inFrame, mIsNotched);
// Clip to revealed rect
RgnHandle revealedRgn = ::NewRgn();
::RectRgn(revealedRgn, &inRevealed);
::SectRgn(boxRgn, revealedRgn, boxRgn);
::DisposeRgn(revealedRgn);
return boxRgn;
}
//
// AGANotchedFocusBoxPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAFocusBoxPP
AGANotchedFocusBoxPP* AGANotchedFocusBoxPP::CreateStream(LStream* inStream)
{
return new AGANotchedFocusBoxPP(inStream);
}
AGANotchedFocusBoxPP::AGANotchedFocusBoxPP()
{
mIsNotched = true;
}
AGANotchedFocusBoxPP::AGANotchedFocusBoxPP(const LFocusBox &inOriginal)
: Inherited(inOriginal)
{
mIsNotched = true;
}
AGANotchedFocusBoxPP::AGANotchedFocusBoxPP(LStream* inStream)
: Inherited(inStream)
{
mIsNotched = true;
}
AGANotchedFocusBoxPP::~AGANotchedFocusBoxPP()
{
}
//
// AGAListBoxPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LListBox
AGAListBoxPP* AGAListBoxPP::CreateStream(LStream* inStream)
{
return new AGAListBoxPP(inStream);
}
AGAListBoxPP::AGAListBoxPP()
{
mNotchedFrame = false;
mNotchedFocusBox = false;
}
AGAListBoxPP::AGAListBoxPP(LStream* inStream)
: Inherited(inStream)
{
mNotchedFrame = false;
mNotchedFocusBox = false;
}
AGAListBoxPP::~AGAListBoxPP()
{
}
void AGAListBoxPP::FinishCreateSelf()
{
// Replace the standard LFocusBox with an AGAFocusBoxPP
// initialized from the existing one.
if (mFocusBox != NULL)
{
AGAFocusBoxPP* newFocusBox;
if (mNotchedFocusBox)
newFocusBox = new AGANotchedFocusBoxPP(*mFocusBox);
else
newFocusBox = new AGAFocusBoxPP(*mFocusBox);
delete mFocusBox;
mFocusBox = newFocusBox;
mFocusBox->AttachPane(this, false);
// The standard LFocusBox is smaller by 1 pixel on each
// side than the AGA focus box, so expand ours from where
// LFocusBox::AttachPane located and sized it.
mFocusBox->MoveBy(-1, -1, true);
mFocusBox->ResizeFrameBy(2, 2, true);
}
// Attach the white background and border frame attachments.
if (mNotchedFrame)
{
this->AddAttachment(new AGANotchedWhiteBackgroundAttachmentPP);
this->AddAttachment(new AGANotchedBorderFrameAttachmentPP);
}
else
{
this->AddAttachment(new AGAWhiteBackgroundAttachmentPP);
this->AddAttachment(new AGABorderFrameAttachmentPP);
}
}
void AGAListBoxPP::DrawSelf()
{
this->DrawEverything(kUseUpdateRgn);
}
void AGAListBoxPP::ActivateSelf()
{
Inherited::ActivateSelf();
Rect frame;
(void) this->CalcLocalFrameRect(frame);
if (this->ExecuteAttachments(msg_DrawOrPrint, &frame))
this->DrawEverything(kDontUseUpdateRgn);
}
void AGAListBoxPP::DeactivateSelf()
{
Inherited::DeactivateSelf();
Rect frame;
(void) this->CalcLocalFrameRect(frame);
if (this->ExecuteAttachments(msg_DrawOrPrint, &frame))
this->DrawEverything(kDontUseUpdateRgn);
}
void AGAListBoxPP::EnableSelf()
{
Rect frame;
(void) this->CalcLocalFrameRect(frame);
if (this->IsVisible())
if (this->ExecuteAttachments(msg_DrawOrPrint, &frame))
this->DrawEverything(kDontUseUpdateRgn);
}
void AGAListBoxPP::DisableSelf()
{
Rect frame;
(void) this->CalcLocalFrameRect(frame);
if (this->IsVisible())
if (this->ExecuteAttachments(msg_DrawOrPrint, &frame))
this->DrawEverything(kDontUseUpdateRgn);
}
void AGAListBoxPP::DrawEverything(Boolean useUpdateRgn)
{
// AGAListBoxPP just isn't set up to handle our situations where dimming
// and background color changes affect the whole view. It tries to
// optimize by not calling LUpdate upon enable/disable messages. But
// our background may change or get painted when that happens. So we catch
// the DrawSelf and other appropriate messages, and just draw it all.
this->FocusDraw();
Rect r;
Boolean enabled = (mEnabled == triState_On);
(void) this->CalcLocalFrameRect(r);
::PenNormal(); // pen size 1,1, solid black pattern, srcOr
::RGBBackColor(&gAGARamp[rW]);
if (enabled)
::RGBForeColor(&gAGARamp[rB]);
else
::RGBForeColor(&gAGARamp[r7]);
GrafPtr savePort = (**mMacListH).port;
(**mMacListH).port = UQDGlobals::GetCurrentPort();
RgnHandle updateRgn;
if (useUpdateRgn)
updateRgn = GetLocalUpdateRgn();
else
{
updateRgn = ::NewRgn();
::RectRgn(updateRgn, &r);
}
::LUpdate(updateRgn, mMacListH);
::DisposeRgn(updateRgn);
(**mMacListH).port = savePort;
// For any non-deep screens, we paint a gray pattern on
// to the text if it's dim. Check the existence of scroll
// bars to determine exactly where we should paint.
if (! enabled)
{
GDIterator iter;
Boolean deep;
ListHandle ourListHandle = this->GetMacListH();
::InsetRect(&r, 1, 1);
if ((**ourListHandle).hScroll != NULL)
r.bottom -= 15; // room for h scroll bar
if ((**ourListHandle).vScroll != NULL)
r.right -= 15; // room for v scroll bar
::PenPat(&qd.gray);
::PenMode(patBic);
while (iter.More(deep))
if (! deep)
::PaintRect(&r);
}
}
//
// AGANotchedListBoxPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGAListBoxPP
AGANotchedListBoxPP* AGANotchedListBoxPP::CreateStream(LStream* inStream)
{
return new AGANotchedListBoxPP(inStream);
}
AGANotchedListBoxPP::AGANotchedListBoxPP()
{
mNotchedFrame = true;
}
AGANotchedListBoxPP::AGANotchedListBoxPP(LStream* inStream)
: Inherited(inStream)
{
mNotchedFrame = true;
}
AGANotchedListBoxPP::~AGANotchedListBoxPP()
{
}
//
// AGANotchedFocusListBoxPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGANotchedListBoxPP
AGANotchedFocusListBoxPP* AGANotchedFocusListBoxPP::CreateStream(LStream* inStream)
{
return new AGANotchedFocusListBoxPP(inStream);
}
AGANotchedFocusListBoxPP::AGANotchedFocusListBoxPP()
{
mNotchedFocusBox = true;
}
AGANotchedFocusListBoxPP::AGANotchedFocusListBoxPP(LStream* inStream)
: Inherited(inStream)
{
mNotchedFocusBox = true;
}
AGANotchedFocusListBoxPP::~AGANotchedFocusListBoxPP()
{
}
//
// AGAPanelEnclosurePP ----------------------------------------------------
//
#undef Inherited
AGAPanelEnclosurePP* AGAPanelEnclosurePP::CreateStream(LStream* inStream)
{
return new AGAPanelEnclosurePP(inStream);
}
AGAPanelEnclosurePP::AGAPanelEnclosurePP(LStream* inStream)
: LView(inStream)
{
}
AGAPanelEnclosurePP::AGAPanelEnclosurePP()
{
}
AGAPanelEnclosurePP::~AGAPanelEnclosurePP()
{
}
void AGAPanelEnclosurePP::SwitchPanelOut()
{
if (this->IsOnDuty())
this->SwitchTarget(NULL);
}
void AGAPanelEnclosurePP::SwitchPanelIn()
{
if (this->GetLatentSub() != NULL)
this->RestoreTarget();
}
//
// AGATabPanelPP ----------------------------------------------------
//
#undef Inherited
#define Inherited LView
AGATabPanelPP* AGATabPanelPP::CreateStream(LStream* inStream)
{
return new AGATabPanelPP(inStream);
}
AGATabPanelPP::AGATabPanelPP(LStream* inStream)
: Inherited(inStream)
{
mAGAObject = NULL;
mLabelsTextTraitsID = 0; // System font is std for large; Geneva 10 bold is std for small
mLabelsResourceID = mUserCon; // STR# resource ID of the slider labels (0 for none)
mPanelContainerView = NULL;
mActivePanelView = NULL;
mTempSupressDisable = false;
}
AGATabPanelPP::AGATabPanelPP()
{
mAGAObject = NULL;
mLabelsTextTraitsID = 0; // System font is std for large; Geneva 10 bold is std for small
mLabelsResourceID = 0; // STR# resource ID of the slider labels (0 for none)
mPanelContainerView = NULL;
mActivePanelView = NULL;
mTempSupressDisable = false;
}
AGATabPanelPP::~AGATabPanelPP()
{
// Delete AGA object if we successfully allocated it.
// We also need to make sure that all panel views not currently
// installed get destructed. Unfortunately, it seems that
// the LStdControl-based classes try to Focus during destruction,
// and don't check to see if they're in a port; this causes
// FocusDraw to throw an exception. So it's easiest if we just
// suck all the panels into our container and let them get deleted
// by LView::DeleteAllSubPanes, which is called by our parent class
// destructor.
if (mAGAObject != NULL)
{
/*
SInt32 numTabs;
numTabs = mAGAObject->GetNumTabs();
for (SInt32 tabIndex = 0; tabIndex < numTabs; tabIndex++)
{
if (tabIndex != mAGAObject->GetCurrentTab())
this->SwitchPanelIn(tabIndex, false); // make it part of the hierarchy for deletion
}
*/
delete mAGAObject;
}
}
void AGATabPanelPP::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGATabPanelPP::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
{
// Let the PowerPlant and AGA objects update their bounds.
Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
ResetAGAObjectFrame(this, mAGAObject);
}
void AGATabPanelPP::FinishCreateSelf()
{
// Create and set up the AGAObject.
this->CreateAGAObject();
// Create the container view that we'll load panels in and out of.
this->CreateContainerView();
}
void AGATabPanelPP::DrawSelf()
{
// Let the AGAObject draw itself.
if (mAGAObject != NULL)
mAGAObject->DrawObject();
}
void AGATabPanelPP::ClickSelf(const SMouseDownEvent &inMouseDown)
{
// Let the AGAObject track the mouse.
if (mAGAObject != NULL)
{
this->FocusDraw();
if (mAGAObject->TrackMouse(inMouseDown.whereLocal))
this->HandleTabSwitch(mAGAObject->GetLastTabClicked());
}
}
void AGATabPanelPP::EnableSelf()
{
// Let the AGAObject enable itself.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kEnabled, this->IsVisible());
}
}
void AGATabPanelPP::DisableSelf()
{
// Let the AGAObject disable itself.
if ((mAGAObject != NULL) && ! mTempSupressDisable)
{
this->FocusDraw();
mAGAObject->SetEnable(AGAObject::kDisabled, this->IsVisible());
}
}
void AGATabPanelPP::CreateAGAObject()
{
// Instantiate the particular AGAObject subclass.
Rect bounds;
(void) this->CalcLocalFrameRect(bounds);
ThrowIfNil_(mAGAObject = new AGATabPanel(&bounds, 0, AGATextStyle(mLabelsTextTraitsID), mLabelsResourceID));
// Tab panel has to erase when drawing, so make sure that
// it doesn't assume we're on a gray background.
this->FocusDraw();
this->ApplyForeAndBackColors();
InstallAGABackgroundColors(mAGAObject, kInstallAlways);
}
void AGATabPanelPP::CreateContainerView()
{
if (mAGAObject->HasFrame()) // if no frame, we just run the tabs, not the panels
{
// Create a subview to contain the panels that we load and unload.
LPane::SetDefaultView(this);
SInt16 tabHeight = mAGAObject->GetTabHeight();
SPaneInfo paneInfo;
SViewInfo viewInfo;
// Init the paneInfo with our own coordinates & bindings.
paneInfo.paneID = 0;
paneInfo.width = mFrameSize.width;
paneInfo.height = mFrameSize.height;
paneInfo.visible = true;
paneInfo.enabled = true;
paneInfo.bindings = mFrameBinding;
paneInfo.left = mFrameLocation.h;
paneInfo.top = mFrameLocation.v;
paneInfo.userCon = 0;
paneInfo.superView = mSuperView;
// Inset the bounds by 4 pixels, plus the tab height at the top.
paneInfo.top += (tabHeight + 4);
paneInfo.left += 4;
paneInfo.height -= (tabHeight + 8);
paneInfo.width -= 8;
// Init the viewInfo with the pane's dimensions.
viewInfo.imageSize.width = paneInfo.width;
viewInfo.imageSize.height = paneInfo.height;
viewInfo.scrollPos.h = 0;
viewInfo.scrollPos.v = 0;
viewInfo.scrollUnit.h = 0;
viewInfo.scrollUnit.v = 0;
viewInfo.reconcileOverhang = 0;
// Create the view and make it a subview of ourself.
mPanelContainerView = new LView(paneInfo, viewInfo);
mPanelContainerView->FinishCreate();
mPanelContainerView->PutInside(this, true);
}
}
void AGATabPanelPP::SetValue(SInt32 inValue)
{
// Switch to the specified tab index.
this->SwitchPanels(inValue);
}
SInt32 AGATabPanelPP::GetValue() const
{
// Return the index of the currently selected tab.
if (mAGAObject == NULL)
return 0;
else
return mAGAObject->GetCurrentTab();
}
void AGATabPanelPP::Disable()
{
// Need to change the way disable works because of the sequence of
// drawing that normally occurs for a view with subpanes. The normal
// sequence draws the parent view (us) after drawing the subpanes,
// which is wrong because our disable drawing has to paint the whole
// pane gray, which covers all subpanes. So instead we get ourself
// to draw disabled first, then let the normal stuff occur while
// setting a flag that tells us to skip the draw disabled message
// that we'll get during that processing. Kinda ugly, but it works.
if (this->IsEnabled())
this->DisableSelf();
mTempSupressDisable = true;
Inherited::Disable();
mTempSupressDisable = false;
}
void AGATabPanelPP::SwitchPanels(SInt32 newTabIndex)
{
// Switch to the specified tab index.
if (mAGAObject != NULL)
{
this->FocusDraw();
mAGAObject->SetCurrentTab(newTabIndex, this->IsVisible());
}
this->SwitchPanelOut();
this->SwitchPanelIn(newTabIndex);
}
void AGATabPanelPP::HandleTabSwitch(SInt32 newTabIndex)
{
// If it's OK to switch tabs (may need to validate current
// panel before switching), do the switch.
if (this->ValidatePanel(mAGAObject->GetCurrentTab()))
this->SetValue(newTabIndex);
}
void AGATabPanelPP::AddPanel(ResIDT panelResourceID, StringPtr tabLabel)
{
// Create a new tab and assign the specified panel to it.
if (mAGAObject != NULL)
{
Str255 actualTabLabel;
SInt32 numTabs;
if (tabLabel != NULL)
AGA_PLstrcpy(actualTabLabel, tabLabel);
else
{
Handle ppobHandle;
SInt16 ppobID;
OSType ppobType;
ThrowIfNil_(ppobHandle = ::GetResource('PPob', panelResourceID));
::GetResInfo(ppobHandle, &ppobID, &ppobType, actualTabLabel);
// Don't release it -- we're about to cause it to be read anyway.
}
numTabs = mAGAObject->GetNumTabs();
mAGAObject->SetNumTabs(numTabs + 1, AGATabPanel::kDontShrink);
this->InstallPanel(numTabs, panelResourceID, actualTabLabel);
}
}
void AGATabPanelPP::InstallPanel(SInt32 tabIndex, ResIDT panelResourceID, StringPtr tabLabel)
{
// Assign the specified panel to the specified tab.
if (mAGAObject != NULL)
{
LView* newPanelView;
SInt32 numTabs;
numTabs = mAGAObject->GetNumTabs();
if (tabIndex < numTabs)
{
// To keep the command chain in an orderly state, we need to create the
// panel view as a subcommander of another commander. In the MacApp world,
// this would just be its superview. But in PowerPlant, LPane is not a
// commander; only certain pane classes mix in LCommander. So we have to
// walk up the superview chain until we find an LCommander subclass object,
// via dynamic casting.
//
// If you bypass the RTTI here, you must ensure that the tab panel view
// lives in a view hierarchy with an LCommander (such as LWindow or LDialogBox)
// at the root.
LCommander* nearestSuperCommander = NULL;
LView* aSuperView = mPanelContainerView;
while ((nearestSuperCommander == NULL) && (aSuperView != NULL))
{
#ifndef NO_RTTI
// Found if this superview is an LCommander.
nearestSuperCommander = dynamic_cast<LCommander*>(aSuperView);
#else // NO_RTTI
// Found if this superview is the root view (window or dialog).
if (aSuperView->GetSuperView() == NULL)
nearestSuperCommander = (LCommander*) aSuperView;
#endif // NO_RTTI
aSuperView = aSuperView->GetSuperView();
}
// Wrap the CreateView with custom color values so that the
// AGA objects in the panel hierarchy will get the right background
// colors.
TurnOnCustomAGABackgroundColors(&gAGARamp[r1], &gAGARamp[r2]);
ThrowIfNil_(newPanelView = UReanimator::CreateView(panelResourceID, mPanelContainerView, nearestSuperCommander));
TurnOffCustomAGABackgroundColors();
newPanelView->Hide();
mAGAObject->SetTabUserData(tabIndex, newPanelView);
if (tabLabel != NULL)
{
mAGAObject->SetTabLabel(tabIndex, tabLabel);
mAGAObject->CalculateTabWidths();
}
// If this panel corresponds to the initial value, switch it in.
if (this->GetValue() == tabIndex)
this->SwitchPanels(tabIndex);
}
}
}
LView* AGATabPanelPP::GetPanelView(SInt32 tabIndex)
{
// Return the top LView* of the specified tab's panel view hierarchy.
if (mAGAObject == NULL)
return NULL;
else
return (LView*) mAGAObject->GetTabUserData(tabIndex);
}
Boolean AGATabPanelPP::ValidatePanel(SInt32 /*currentTabIndex*/)
{
// (Override for app-specific validation.)
//
// Return true if the current (specified) panel is valid and
// it's OK to switch to a different panel. Return false otherwise
// and the tab switch will not occur; it's OK to alert the user
// of the invalid data before returning false.
//
return true;
}
void AGATabPanelPP::SwitchPanelOut()
{
// Make the current panel invisible and disabled.
if (mActivePanelView != NULL)
{
#ifndef NO_RTTI
// If the current panel root is an AGAPanelEnclosurePP,
// we can give it a chance to clean up its target.
// If you bypass the RTTI here, the current panel may not
// give up the target.
AGAPanelEnclosurePP* enclosure = dynamic_cast<AGAPanelEnclosurePP*>(mActivePanelView);
if (enclosure != NULL)
enclosure->SwitchPanelOut();
#endif // NO_RTTI
mActivePanelView->Hide();
mActivePanelView->Disable();
mActivePanelView = NULL;
}
}
void AGATabPanelPP::SwitchPanelIn(SInt32 newTabIndex)
{
// Make the specified tab's panel visible and enabled.
if (mAGAObject != NULL)
{
LView* newPanelView = (LView*) mAGAObject->GetTabUserData(newTabIndex);
if (newPanelView != NULL)
{
mActivePanelView = newPanelView;
newPanelView->Enable();
newPanelView->Show();
// If the current panel root is an AGAPanelEnclosurePP,
// we can give it a chance to restore its target.
// If you bypass the RTTI here, the new panel may not
// grab the target.
#ifndef NO_RTTI
AGAPanelEnclosurePP* enclosure = dynamic_cast<AGAPanelEnclosurePP*>(newPanelView);
if (enclosure != NULL)
enclosure->SwitchPanelIn();
#endif // NO_RTTI
}
}
}
//
// AGATabPanelPPX ----------------------------------------------------
//
#undef Inherited
#define Inherited AGATabPanelPP
AGATabPanelPPX* AGATabPanelPPX::CreateStream(LStream* inStream)
{
return new AGATabPanelPPX(inStream);
}
AGATabPanelPPX::AGATabPanelPPX(LStream* inStream)
: Inherited(inStream)
{
// Read the labels STR# ID and labels text traits ID from the stream.
inStream->ReadData(&mLabelsResourceID, sizeof(mLabelsResourceID));
inStream->ReadData(&mLabelsTextTraitsID, sizeof(mLabelsTextTraitsID));
}
AGATabPanelPPX::~AGATabPanelPPX()
{
}
//
// AGASmallTabPanelPP ----------------------------------------------------
//
#undef Inherited
#define Inherited AGATabPanelPP
AGASmallTabPanelPP* AGASmallTabPanelPP::CreateStream(LStream* inStream)
{
return new AGASmallTabPanelPP(inStream);
}
AGASmallTabPanelPP::AGASmallTabPanelPP(LStream* inStream)
: Inherited(inStream)
{
}
AGASmallTabPanelPP::~AGASmallTabPanelPP()
{
}
void AGASmallTabPanelPP::CreateAGAObject()
{
Inherited::CreateAGAObject();
// Set the tabs to use the standard small appearance.
mAGAObject->SetTabSize(AGATabPanel::kSmallTabs);
mAGAObject->SetLabelsStyle(gAGAStdBoldSmallStyle);
}